Core Functions
Fundamental operations available everywhere: I/O, type casting, assertions, and basic arithmetic. These 17 functions form the bedrock of every BioLang program.
Write values to standard output without a trailing newline. Multiple arguments are separated by a single space.
print(values...) -> nil
| Parameter | Type | Description |
|---|---|---|
| values | any (variadic) | One or more values to print |
Returns: nil
print("GC content: ", 0.42) # GC content: 0.42
print("chr", 1) # chr1
println
Write values to standard output followed by a newline. The primary output function in BioLang.
println(values...) -> nil
| Parameter | Type | Description |
|---|---|---|
| values | any (variadic) | One or more values to print |
Returns: nil
println("Hello, BioLang!") # Hello, BioLang!\n
println("Reads:", 1_000_000) # Reads: 1000000\n
println([1, 2, 3]) # [1, 2, 3]\n
len
Return the length of a string (bytes), list (elements), or map (keys). Raises an error on types without a meaningful length.
len(value) -> int
| Parameter | Type | Description |
|---|---|---|
| value | string | list | map | Value to measure |
Returns: int
len("ATCGATCG") # 8
len([10, 20, 30]) # 3
len({"a": 1, "b": 2}) # 2
Edge case: For strings, len returns byte count, not character count. For multibyte UTF-8 characters, use len(split(s, "")) to get grapheme count.
type
Return the type name of a value as a string. Useful for runtime type checks and debugging.
type(value) -> string
| Parameter | Type | Description |
|---|---|---|
| value | any | Any value |
Returns: string — one of: "int", "float", "string", "bool", "list", "map", "nil", "function", "table", "matrix", "sparse", "datetime", "svg"
type(42) # "int"
type(3.14) # "float"
type("ACGT") # "string"
type([1, 2]) # "list"
type(nil) # "nil"
type(len) # "function"
range
Generate a list of integers from start (inclusive) to end (exclusive) with an optional step.
range(start, end, step?) -> list
| Parameter | Type | Description |
|---|---|---|
| start | int | Start value (inclusive) |
| end | int | End value (exclusive) |
| step | int (optional) | Step increment (default: 1) |
Returns: list<int>
range(0, 5) # [0, 1, 2, 3, 4]
range(1, 10, 2) # [1, 3, 5, 7, 9]
range(10, 0, -2) # [10, 8, 6, 4, 2]
range(0, 0) # []
Edge case: A step of 0 raises an error. Mismatched signs (e.g., range(0, 5, -1)) return an empty list.
abs
Return the absolute value of a number.
abs(n) -> number
| Parameter | Type | Description |
|---|---|---|
| n | int | float | Numeric value |
Returns: number (same type as input)
abs(-42) # 42
abs(3.14) # 3.14
abs(-2.5) # 2.5
# Common use: fold-change magnitude
let fc = -3.2
println("Magnitude:", abs(fc)) # Magnitude: 3.2
min
Return the smaller of two values. Also accepts a list to find the minimum element.
min(a, b) -> number
min(list) -> number
| Parameter | Type | Description |
|---|---|---|
| a, b | number | Two values to compare |
| list | list<number> | List of numbers |
Returns: number
min(3, 7) # 3
min([28, 15, 42, 3]) # 3
let quality_scores = [30, 28, 35, 22, 31]
println("Min Q:", min(quality_scores)) # Min Q: 22
max
Return the larger of two values. Also accepts a list to find the maximum element.
max(a, b) -> number
max(list) -> number
| Parameter | Type | Description |
|---|---|---|
| a, b | number | Two values to compare |
| list | list<number> | List of numbers |
Returns: number
max(3, 7) # 7
max([28, 15, 42, 3]) # 42
let coverage = [12, 45, 89, 102, 67]
println("Peak coverage:", max(coverage)) # Peak coverage: 102
int
Cast a value to integer. Floats are truncated. Strings are parsed. Booleans become 0/1.
int(value) -> int
| Parameter | Type | Description |
|---|---|---|
| value | any | Value to convert |
Returns: int
int(3.7) # 3 (truncates, does not round)
int("42") # 42
int(true) # 1
int(false) # 0
int("0xFF") # 255 (hex literals supported)
Edge case: int("abc") raises a parse error. Use is_num() to guard conversions from untrusted input.
float
Cast a value to a 64-bit floating point number.
float(value) -> float
| Parameter | Type | Description |
|---|---|---|
| value | any | Value to convert |
Returns: float
float(42) # 42.0
float("3.14") # 3.14
float("1e-5") # 0.00001
float(true) # 1.0
str
Convert any value to its string representation.
str(value) -> string
| Parameter | Type | Description |
|---|---|---|
| value | any | Value to convert |
Returns: string
str(42) # "42"
str(3.14) # "3.14"
str(true) # "true"
str([1, 2, 3]) # "[1, 2, 3]"
str(nil) # "nil"
bool
Cast a value to boolean. Falsy values: nil, false, 0, 0.0, "", []. Everything else is truthy.
bool(value) -> bool
| Parameter | Type | Description |
|---|---|---|
| value | any | Value to convert |
Returns: bool
bool(1) # true
bool(0) # false
bool("") # false
bool("ACGT") # true
bool([]) # false
bool([1]) # true
bool(nil) # false
assert
Assert that a condition is truthy. If the condition is falsy, execution halts with an error message.
assert(condition, message?) -> nil
| Parameter | Type | Description |
|---|---|---|
| condition | any | Value to test for truthiness |
| message | string (optional) | Custom error message |
Returns: nil (or halts on failure)
let reads = 1_000_000
assert(reads > 0, "Expected positive read count")
let seq = "ATCGATCG"
assert(len(seq) % 3 == 0, "Sequence length not divisible by 3")
# Error: Assertion failed: Sequence length not divisible by 3
debug
Print the debug representation of a value to stderr and return the value unchanged. Useful for inspecting intermediate values in pipelines.
debug(value) -> value
| Parameter | Type | Description |
|---|---|---|
| value | any | Value to inspect |
Returns: any (passthrough)
# Inspect inside a pipeline
let result = [1, 2, 3]
|> map(|x| x * 2)
|> debug # stderr: [2, 4, 6]
|> filter(|x| x > 3)
|> debug # stderr: [4, 6]
typeof
Alias for type(). Returns the type name of a value as a string.
typeof(value) -> string
typeof(42) # "int"
typeof("ACGT") # "string"
is_nil
Check if a value is nil. More explicit than value == nil.
is_nil(value) -> bool
| Parameter | Type | Description |
|---|---|---|
| value | any | Value to check |
Returns: bool
is_nil(nil) # true
is_nil(0) # false
is_nil("") # false
is_nil(false) # false
let result = find([1, 2, 3], |x| x > 10)
if is_nil(result) {
println("Not found")
}
to_string
Alias for str(). Convert any value to its string representation.
to_string(value) -> string
to_string(42) # "42"
to_string([1, 2, 3]) # "[1, 2, 3]"
tap
Passes a value through a callback as a side effect, then returns the original value unchanged. Useful for logging or debugging inside pipelines.
# Debug a pipeline without breaking the chain
reads
|> filter(|r| r.quality > 20)
|> tap(|x| println("After filter:", len(x), "reads"))
|> map(|r| r.sequence)
|> tap(|x| println("Sequences:", len(x)))
# Inspect intermediate value
let result = data
|> tap(|d| println("Input rows:", nrow(d)))
|> mutate("score", |r| r.val * 2)
Genomic Units
Unit conversion functions return integer base-pair counts, so arithmetic composes naturally.
| Function | Description | Example |
|---|---|---|
bp(n) | Base pairs (identity) | bp(500) → 500 |
kb(n) | Kilobases × 1,000 | kb(1.5) → 1500 |
mb(n) | Megabases × 1,000,000 | mb(3) → 3000000 |
gb(n) | Gigabases × 1,000,000,000 | gb(3.1) → 3100000000 |
# Composable arithmetic
let window = kb(500) + bp(200) # 500200
let genome_size = gb(3.1) # 3100000000
# Use in interval operations
let region_size = mb(1)
let start = kb(100)
let end = start + region_size # 1100000