Core Functions

Fundamental operations available everywhere: I/O, type casting, assertions, and basic arithmetic. These 17 functions form the bedrock of every BioLang program.

print

Write values to standard output without a trailing newline. Multiple arguments are separated by a single space.

print(values...) -> nil
ParameterTypeDescription
valuesany (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
ParameterTypeDescription
valuesany (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
ParameterTypeDescription
valuestring | list | mapValue 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
ParameterTypeDescription
valueanyAny 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
ParameterTypeDescription
startintStart value (inclusive)
endintEnd value (exclusive)
stepint (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
ParameterTypeDescription
nint | floatNumeric 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
ParameterTypeDescription
a, bnumberTwo values to compare
listlist<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
ParameterTypeDescription
a, bnumberTwo values to compare
listlist<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
ParameterTypeDescription
valueanyValue 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
ParameterTypeDescription
valueanyValue 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
ParameterTypeDescription
valueanyValue 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
ParameterTypeDescription
valueanyValue 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
ParameterTypeDescription
conditionanyValue to test for truthiness
messagestring (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
ParameterTypeDescription
valueanyValue 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
ParameterTypeDescription
valueanyValue 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,000kb(1.5)1500
mb(n)Megabases × 1,000,000mb(3)3000000
gb(n)Gigabases × 1,000,000,000gb(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