Modules & Imports
BioLang's module system lets you split code across .bl files and
load them with import. All top-level bindings in a file are
exported automatically — there is no pub keyword.
Note:
Import and file operations require the CLI (bl run).
The examples on this page are not runnable in the browser playground.
import “path”
The basic import statement loads and executes a .bl file.
The file's top-level bindings become available in the current scope:
# Load a file — all its top-level let/fn bindings are imported
import "helpers.bl"
# With an alias — access bindings as qc.check_quality(), qc.VERSION, etc.
import "lib/qc.bl" as qc
let result = qc.check_quality(reads)
println(f"Pass rate: {result.pass_rate}")
from “path” import names
To pull specific names into scope without an alias, use the
from ... import form:
# Import only the bindings you need
from "lib/qc.bl" import check_quality, check_contamination
let qc = check_quality(reads)
println(f"Fail rate: {qc.fail_rate}")
Module Caching
Each module is loaded and evaluated once, then cached by its canonical file path. Subsequent imports of the same file (from any location) reuse the cached result:
# a.bl
import "shared.bl" # loads and caches shared.bl
# b.bl
import "shared.bl" # reuses the cached module — not re-executed
# Circular imports are detected and rejected at load time.
What Gets Exported
All top-level let and fn bindings in a file are
visible to importers. There is no pub / private distinction.
To keep something internal, put it inside a function rather than at the top level:
# File: qc.bl
# These are exported (top-level):
let VERSION = "1.0.0"
fn check_quality(reads, min_q) {
# This helper is NOT exported — it's defined inside a function
let compute_threshold = |scores| mean(scores) - 2.0 * stdev(scores)
let threshold = compute_threshold(reads |> map(|r| r.quality))
reads |> filter(|r| r.quality >= threshold)
}
Plugin System
When a path does not resolve to a file, BioLang looks for a matching plugin
in ~/.biolang/plugins/. Plugins follow a subprocess JSON protocol
and can be written in Python, R, TypeScript, or as native binaries:
# Install a plugin from the CLI:
# $ bl add blast
# Then import it like a regular module:
import "blast" as blast
let hits = blast.blastn(query, db, evalue: 1e-10)
Project Structure
A typical BioLang project organizes modules by domain:
my-analysis/
main.bl # Entry point (bl run main.bl)
lib/
qc.bl # Quality control functions
alignment.bl # Alignment helpers
variant.bl # Variant calling utilities
data/
samples.csv
results/
# main.bl
import "lib/qc.bl" as qc
import "lib/alignment.bl" as align
from "lib/variant.bl" import call_and_filter
let samples = read_csv("data/sample_sheet.csv")
for sample in samples {
let quality = qc.check(sample)
let bam = align.run(sample)
let variants = call_and_filter(bam)
println(f"{sample.id}: {len(variants)} variants found")
}