Mutating-function convention. Function names ending in ! mutate their first argument in place; names without ! return new values and leave their inputs untouched. ! is part of the identifier — push and push! are different functions. The convention is not enforced; users may name a mutating function with or without ! as they prefer.
m[k] = v#[…] vectors & maps: length, isEmpty, push, put, get, remove, contains, keys, values, merge, toPersistentVector, toArray, toPersistentMap, toMapThese functions are overloaded across multiple numeric types.
abs(x)Returns the absolute value of x.
| Signature | Description |
|---|---|
abs(Int) → Int | Absolute value of an integer. |
abs(Float) → Float | Absolute value of a float. |
abs(Fraction) → Fraction | Absolute value of a fraction. |
abs(Complex) → Float | Magnitude (modulus) of a complex number. |
-5 abs -- 5
-3.14 abs -- 3.14
(3+4i) abs -- 5.0
sign(x)Returns -1, 0, or 1 indicating the sign of x.
| Signature | Description |
|---|---|
sign(Int) → Int | Sign of an integer. |
sign(Float) → Int | Sign of a float. |
sign(Fraction) → Int | Sign of a fraction. |
min(a, b)Returns the smaller of two values.
| Signature | Description |
|---|---|
min(Int, Int) → Int | Minimum of two integers. |
min(Float, Float) → Float | Minimum of two floats. |
min(Fraction, Fraction) → Fraction | Minimum of two fractions. |
min(String, String) → String | Lexicographically smaller of two strings. |
max(a, b)Returns the larger of two values.
| Signature | Description |
|---|---|
max(Int, Int) → Int | Maximum of two integers. |
max(Float, Float) → Float | Maximum of two floats. |
max(Fraction, Fraction) → Fraction | Maximum of two fractions. |
max(String, String) → String | Lexicographically larger of two strings. |
clamp(x, lo, hi)Clamps x to the range [lo, hi].
| Signature | Description |
|---|---|
clamp(Int, Int, Int) → Int | Clamp an integer to a range. |
clamp(Float, Float, Float) → Float | Clamp a float to a range. |
clamp(Fraction, Fraction, Fraction) → Fraction | Clamp a fraction to a range. |
15 clamp(0, 10) -- 10
-5 clamp(0, 10) -- 0
5 clamp(0, 10) -- 5
cmp(a, b)Three-way comparison. Returns -1 if a < b, 0 if a == b, 1 if a > b.
| Signature | Description |
|---|---|
cmp(Int, Int) → Int | Compare two integers. |
cmp(Float, Float) → Int | Compare two floats. |
cmp(Fraction, Fraction) → Int | Compare two fractions. |
cmp(String, String) → Int | Lexicographic comparison of two strings. |
gcd(a, b)Greatest common divisor of two integers. Always returns a non-negative result.
| Signature | Description |
|---|---|
gcd(Int, Int) → Int | Greatest common divisor. |
gcd(12, 8) -- 4
gcd(7, 13) -- 1
gcd(0, 5) -- 5
gcd(-12, 8) -- 4
lcm(a, b)Least common multiple of two integers. Returns 0 if either argument is 0. Always returns a non-negative result.
| Signature | Description |
|---|---|
lcm(Int, Int) → Int | Least common multiple. |
lcm(4, 6) -- 12
lcm(7, 13) -- 91
lcm(0, 5) -- 0
lcm(-4, 6) -- 12
↑ Back to top
Random number functions use a per-VM xoshiro256** generator, seeded from the system entropy source at VM creation. Each VM instance has its own independent RNG state. These functions are never constant-folded.
urand()Returns a uniform random Float in the range [0.0, 1.0).
| Signature | Description |
|---|---|
urand() → Float | Uniform random float in [0.0, 1.0). |
urand() -- e.g. 0.7320508075688772
urands() / urands(n)Multiple uniform random floats in [0.0, 1.0). With no arguments, returns an infinite lazy list. With one argument, returns an array of n values.
| Signature | Description |
|---|---|
urands() → List<Float> | Infinite lazy list of uniform random floats. |
urands(Int) → [Float] | Array of n uniform random floats. |
urands() take(3) -- e.g. List(0.312, 0.449, 0.641)
urands(4) -- e.g. [0.041, 0.718, 0.013, 0.554]
brand()Returns a bipolar random Float in the range [-1.0, 1.0).
| Signature | Description |
|---|---|
brand() → Float | Bipolar random float in [-1.0, 1.0). |
brand() -- e.g. -0.4142135623730951
brands() / brands(n)Multiple bipolar random floats in [-1.0, 1.0). With no arguments, returns an infinite lazy list. With one argument, returns an array of n values.
| Signature | Description |
|---|---|
brands() → List<Float> | Infinite lazy list of bipolar random floats. |
brands(Int) → [Float] | Array of n bipolar random floats. |
brands() take(3) -- e.g. List(-0.945, 0.620, -0.570)
brands(4) -- e.g. [0.232, -0.846, -0.553, 0.714]
irand(lo, hi)Returns a uniform random Int in the inclusive range [lo, hi]. Uses unbiased rejection sampling. If lo > hi, the arguments are swapped.
| Signature | Description |
|---|---|
irand(Int, Int) → Int | Uniform random integer in [lo, hi]. |
irand(1, 6) -- e.g. 4 (simulates a die roll)
irand(0, 99) -- e.g. 42
irands(lo, hi) / irands(n, lo, hi)Multiple uniform random integers in [lo, hi]. With two arguments, returns an infinite lazy list. With three arguments, the first is the count n and returns an array.
| Signature | Description |
|---|---|
irands(Int, Int) → List<Int> | Infinite lazy list of uniform random integers in [lo, hi]. |
irands(Int, Int, Int) → [Int] | Array of n uniform random integers in [lo, hi]. |
irands(1, 6) take(5) -- e.g. List(3, 6, 1, 4, 2)
irands(4, 1, 6) -- e.g. [5, 2, 6, 1]
rand(lo, hi)Returns a uniform random Float in the range [lo, hi).
| Signature | Description |
|---|---|
rand(Float, Float) → Float | Uniform random float in [lo, hi). |
rand(5.0, 10.0) -- e.g. 7.764822845349203
rand(-1.0, 1.0) -- e.g. -0.271028337412
rands(lo, hi) / rands(n, lo, hi)Multiple uniform random floats in [lo, hi). With two arguments, returns an infinite lazy list. With three arguments, the first is the count n and returns an array.
| Signature | Description |
|---|---|
rands(Float, Float) → List<Float> | Infinite lazy list of uniform random floats in [lo, hi). |
rands(Int, Float, Float) → [Float] | Array of n uniform random floats in [lo, hi). |
rands(5.0, 10.0) take(3) -- e.g. List(8.41, 7.51, 7.24)
rands(4, 5.0, 10.0) -- e.g. [6.07, 5.49, 6.27, 6.92]
xrand(lo, hi)Returns an exponentially distributed random Float in [lo, hi). Computed as lo * pow(hi/lo, urand()). Useful for generating values that span several orders of magnitude with equal probability per octave (e.g. frequencies, durations).
| Signature | Description |
|---|---|
xrand(Float, Float) → Float | Exponentially distributed float in [lo, hi). |
xrand(20.0, 20000.0) -- e.g. 632.4555320336759 (random frequency)
xrand(0.01, 10.0) -- e.g. 0.2154434690031882 (random duration)
xrands(lo, hi) / xrands(n, lo, hi)Multiple exponentially distributed random floats in [lo, hi). With two arguments, returns an infinite lazy list. With three arguments, the first is the count n and returns an array.
| Signature | Description |
|---|---|
xrands(Float, Float) → List<Float> | Infinite lazy list of exponentially distributed floats in [lo, hi). |
xrands(Int, Float, Float) → [Float] | Array of n exponentially distributed floats in [lo, hi). |
xrands(20.0, 20000.0) take(3) -- e.g. List(632.5, 47.8, 8841.2)
xrands(4, 0.01, 10.0) -- e.g. [0.215, 3.42, 0.078, 1.56]
pick(a)Returns a randomly chosen element from the array a.
| Signature | Description |
|---|---|
pick([T]) → T | Choose a random element from the array. |
pick([1, 2, 3, 4, 5]) -- e.g. 3
pick(["red", "green", "blue"]) -- e.g. "green"
picks(a) / picks(a, n)Returns random elements chosen from the array a. With one argument, returns an infinite lazy list of random picks. With two arguments, returns an array of n random picks.
| Signature | Description |
|---|---|
picks([T]) → List<T> | Infinite lazy list of random picks from the array. |
picks([T], Int) → [T] | Array of n random picks from the array. |
picks([1, 2, 3]) take(5) -- e.g. List(2, 1, 3, 3, 1)
picks(["a", "b", "c"], 4) -- e.g. ["b", "a", "c", "a"]
↑ Back to top
All rounding functions take a Float and return a Float.
| Function | Signature | Description |
|---|---|---|
floor(x) | Float → Float | Largest integer value ≤ x. |
ceil(x) | Float → Float | Smallest integer value ≥ x. |
round(x) | Float → Float | Round to nearest integer (halfway cases round away from zero). |
trunc(x) | Float → Float | Round toward zero (drop the fractional part). |
frac(x) | Float → Float | Fractional part: x - floor(x). |
3.7 floor -- 3.0
3.2 ceil -- 4.0
2.5 round -- 3.0
-3.7 trunc -- -3.0
3.75 frac -- 0.75
↑ Back to top
| Function | Signature | Description |
|---|---|---|
sqrt(x) | Float → Float | Square root. |
sqrt(z) | Complex → Complex | Complex square root. |
cbrt(x) | Float → Float | Cube root. |
pow(x, y) | (Float, Float) → Float | Raise x to the power y. |
pow(n, e) | (Int, Int) → Int | Integer power (exponentiation by squaring). Negative exponents truncate toward zero: bases 1 / -1 keep their reciprocal, anything else gives 0. |
pow(q, e) | (Fraction, Int) → Fraction | Exact rational power. Negative exponents invert the base: pow(3/4, -2) is 16/9. |
pow(z, w) | (Complex, Complex) → Complex | Complex power. |
hypot(x, y) | (Float, Float) → Float | Hypotenuse: sqrt(x² + y²) without overflow. |
remainder(x, y) | (Float, Float) → Float | IEEE remainder of x / y. Result is x − n*y where n is the nearest integer to x/y. |
16.0 sqrt -- 4.0
27.0 cbrt -- 3.0
pow(2.0, 10.0) -- 1024.0
hypot(3.0, 4.0) -- 5.0
remainder(5.5, 2.0) -- -0.5
↑ Back to top
| Function | Signature | Description |
|---|---|---|
exp(x) | Float → Float | ex |
exp(z) | Complex → Complex | Complex exponential. |
exp2(x) | Float → Float | 2x |
exp10(x) | Float → Float | 10x |
expm1(x) | Float → Float | ex − 1, accurate for small x. |
log(x) | Float → Float | Natural logarithm (base e). |
log(z) | Complex → Complex | Complex natural logarithm. |
log2(x) | Float → Float | Base-2 logarithm. |
log10(x) | Float → Float | Base-10 logarithm. |
log1p(x) | Float → Float | log(1 + x), accurate for small x. |
1.0 exp -- 2.718281828...
1.0 exp log -- 1.0
1024.0 log2 -- 10.0
1000.0 log10 -- 3.0
↑ Back to top
Standard trigonometric functions operate in radians. The sinpi, cospi, and tanpi variants compute sin(πx), cos(πx), and tan(πx) with better accuracy at exact multiples.
| Function | Signature | Description |
|---|---|---|
sin(x) | Float → Float | Sine. |
sin(z) | Complex → Complex | Complex sine. |
cos(x) | Float → Float | Cosine. |
cos(z) | Complex → Complex | Complex cosine. |
tan(x) | Float → Float | Tangent. |
tan(z) | Complex → Complex | Complex tangent. |
| Function | Signature | Description |
|---|---|---|
asin(x) | Float → Float | Arcsine. Result in [−π/2, π/2]. |
asin(z) | Complex → Complex | Complex arcsine. |
acos(x) | Float → Float | Arccosine. Result in [0, π]. |
acos(z) | Complex → Complex | Complex arccosine. |
atan(x) | Float → Float | Arctangent. Result in [−π/2, π/2]. |
atan(z) | Complex → Complex | Complex arctangent. |
atan2(y, x) | (Float, Float) → Float | Two-argument arctangent. Result in [−π, π]. |
| Function | Signature | Description |
|---|---|---|
sinpi(x) | Float → Float | sin(π · x). Exact at integer values. |
cospi(x) | Float → Float | cos(π · x). Exact at half-integer values. |
tanpi(x) | Float → Float | tan(π · x). |
0.0 sin -- 0.0
1.0 sinpi -- 0.0 (exact)
0.5 cospi -- 0.0 (exact)
atan2(1.0, 1.0) -- 0.7853... (pi/4)
↑ Back to top
| Function | Signature | Description |
|---|---|---|
sinh(x) | Float → Float | Hyperbolic sine. |
sinh(z) | Complex → Complex | Complex hyperbolic sine. |
cosh(x) | Float → Float | Hyperbolic cosine. |
cosh(z) | Complex → Complex | Complex hyperbolic cosine. |
tanh(x) | Float → Float | Hyperbolic tangent. |
tanh(z) | Complex → Complex | Complex hyperbolic tangent. |
asinh(x) | Float → Float | Inverse hyperbolic sine. |
asinh(z) | Complex → Complex | Complex inverse hyperbolic sine. |
acosh(x) | Float → Float | Inverse hyperbolic cosine. |
acosh(z) | Complex → Complex | Complex inverse hyperbolic cosine. |
atanh(x) | Float → Float | Inverse hyperbolic tangent. |
atanh(z) | Complex → Complex | Complex inverse hyperbolic tangent. |
| Function | Signature | Description |
|---|---|---|
erf(x) | Float → Float | Error function. |
erfc(x) | Float → Float | Complementary error function: 1 − erf(x). |
tgamma(x) | Float → Float | Gamma function: Γ(x). |
lgamma(x) | Float → Float | Natural log of the absolute value of Γ(x). |
5.0 tgamma -- 24.0 (i.e. 4!)
0.0 erf -- 0.0
↑ Back to top
| Function | Signature | Description |
|---|---|---|
copysign(x, y) | (Float, Float) → Float | Returns x with the sign of y. |
nextafter(x, y) | (Float, Float) → Float | Next representable float from x toward y. |
| Function | Signature | Description |
|---|---|---|
isNan(x) | Float → Bool | true if x is NaN (not a number). |
isInf(x) | Float → Bool | true if x is positive or negative infinity. |
isFinite(x) | Float → Bool | true if x is neither NaN nor infinity. |
isNormal(x) | Float → Bool | true if x is a normal floating-point number (not zero, subnormal, infinite, or NaN). |
isNan(0.0 / 0.0) -- true
isInf(1.0 / 0.0) -- true
42.0 isFinite -- true
↑ Back to top
These functions operate on Int values, treating them as 64-bit unsigned quantities where applicable.
| Function | Signature | Description |
|---|---|---|
clz(x) | Int → Int | Count leading zeros. Returns 64 if x is 0. |
clo(x) | Int → Int | Count leading ones. |
ctz(x) | Int → Int | Count trailing zeros. Returns 64 if x is 0. |
cto(x) | Int → Int | Count trailing ones. |
popCount(x) | Int → Int | Count the number of set (1) bits. |
| Function | Signature | Description |
|---|---|---|
rotl(x, n) | (Int, Int) → Int | Rotate bits left by n positions. |
rotr(x, n) | (Int, Int) → Int | Rotate bits right by n positions. |
| Function | Signature | Description |
|---|---|---|
bitCeil(x) | Int → Int | Smallest power of 2 ≥ x. |
bitFloor(x) | Int → Int | Largest power of 2 ≤ x. |
bitWidth(x) | Int → Int | Number of bits needed to represent x. |
hasSingleBit(x) | Int → Bool | true if exactly one bit is set (i.e., x is a power of 2). |
1 clz -- 63
0xFF popCount -- 8
5 bitCeil -- 8
5 bitFloor -- 4
8 hasSingleBit -- true
6 hasSingleBit -- false
↑ Back to top
Functions for constructing and decomposing complex numbers. Many standard math functions (sqrt, sin, cos, exp, log, pow, etc.) also have Complex overloads listed in their respective sections above.
Complex(real, imag)Construct a complex number from real and imaginary parts. Both arguments are promoted to Float.
| Signature | Description |
|---|---|
Complex(Numeric, Numeric) → Complex | Create a complex number. Both arguments are converted to Float. |
Complex(3.0, 4.0) -- 3.0+4.0i
Complex(1, 0) -- 1.0+0.0i
| Function | Signature | Description |
|---|---|---|
real(z) | Complex → Float | Extract the real part. |
imag(z) | Complex → Float | Extract the imaginary part. |
arg(z) | Complex → Float | Phase angle (argument) in radians. Result in [−π, π]. |
norm(z) | Complex → Float | Squared magnitude: real² + imag². |
conj(z) | Complex → Complex | Complex conjugate: if z = a+bi, then conj(z) = a-bi. |
polar(r, θ) | (Float, Float) → Complex | Create complex from polar coordinates: r · (cosθ + i·sinθ). |
let z = 3.0 + 4.0i
z real -- 3.0
z imag -- 4.0
z abs -- 5.0
z norm -- 25.0
z conj -- 3.0-4.0i
z arg -- 0.9272... (radians)
polar(5.0, 0.0) -- 5.0+0.0i
↑ Back to top
A Fraction is an exact rational number written with the / operator between two integers, e.g. 7/2. Fractions are always stored in lowest terms with a positive denominator; any sign is carried by the numerator (6/(-8) becomes -3/4). Fractions sit between Int and Float in the numeric tower, so they participate in the usual implicit conversions and arithmetic (see Type Conversions for toFraction, toFloat, etc.).
| Function | Signature | Description |
|---|---|---|
numer(x) | Fraction → Int | Numerator of the reduced fraction. Carries the sign of the value. |
denom(x) | Fraction → Int | Denominator of the reduced fraction. Always positive. |
numer(7/2) println; -- 7
denom(7/2) println; -- 2
-- Values are reduced to lowest terms first
numer(4/6) println; -- 2
denom(4/6) println; -- 3
-- The sign lives in the numerator; the denominator stays positive
numer(6/(-8)) println; -- -3
denom(6/(-8)) println; -- 4
-- An integer-valued fraction reduces to denominator 1
denom(10/5) println; -- 1
↑ Back to top
Functions that operate on String values. Strings store UTF-8 bytes. Comparisons and cmp use lexicographic (byte-wise) ordering.
| Function | Signature | Description |
|---|---|---|
length(s) | String → Int | Number of bytes in the string. |
isEmpty(s) | String → Bool | True when the string has no bytes. |
min(a, b) | (String, String) → String | Lexicographically smaller string. |
max(a, b) | (String, String) → String | Lexicographically larger string. |
cmp(a, b) | (String, String) → Int | Returns −1, 0, or 1. |
"hello" length -- 5
"" length -- 0
min("apple", "banana") -- "apple"
max("apple", "banana") -- "banana"
cmp("apple", "banana") -- -1
"abc" < "abd" -- true
substring(s, start, len)Returns a substring starting at byte offset start with at most len bytes.
| Signature | Description |
|---|---|
substring(String, Int, Int) → String | Extract a substring by byte position and length. |
substring("hello world", 0, 5) -- "hello"
substring("hello world", 6, 5) -- "world"
substring("abcdef", 2, 3) -- "cde"
contains(s, sub)Returns true if the string contains the given substring.
| Signature | Description |
|---|---|
contains(String, String) → Bool | Test whether sub appears anywhere in s. |
contains("hello world", "world") -- true
contains("hello world", "xyz") -- false
contains("abc", "") -- true
startsWith(s, prefix)Returns true if the string begins with prefix.
| Signature | Description |
|---|---|
startsWith(String, String) → Bool | Test for a prefix match. |
startsWith("hello world", "hello") -- true
startsWith("hello world", "world") -- false
endsWith(s, suffix)Returns true if the string ends with suffix.
| Signature | Description |
|---|---|
endsWith(String, String) → Bool | Test for a suffix match. |
endsWith("hello world", "world") -- true
endsWith("hello world", "hello") -- false
split(s, delimiter)Splits a string by the given delimiter and returns an array of substrings. An empty delimiter splits into individual bytes.
| Signature | Description |
|---|---|
split(String, String) → [String] | Split string by delimiter. |
split("a,b,c", ",") -- ["a", "b", "c"]
split("one--two--three", "--") -- ["one", "two", "three"]
split("hello", "") -- ["h", "e", "l", "l", "o"]
trim(s)Returns a new string with leading and trailing whitespace removed.
| Signature | Description |
|---|---|
trim(String) → String | Strip leading and trailing whitespace. |
trim(" hello ") -- "hello"
trim(" leading") -- "leading"
trim("trailing ") -- "trailing"
toUpper(s) / toLower(s)Returns a new string with all ASCII letters converted to upper or lower case.
| Signature | Description |
|---|---|
toUpper(String) → String | Convert to upper case. |
toLower(String) → String | Convert to lower case. |
toUpper("hello") -- "HELLO"
toLower("HELLO") -- "hello"
toUpper("Hello World") -- "HELLO WORLD"
toLower("Hello World") -- "hello world"
replace(s, from, to)Returns a new string with all occurrences of from replaced by to.
| Signature | Description |
|---|---|
replace(String, String, String) → String | Replace all occurrences of a substring. |
replace("hello world", "world", "there") -- "hello there"
replace("aabbcc", "bb", "XX") -- "aaXXcc"
replace("abcabc", "abc", "x") -- "xx"
indexOf(s, needle) / lastIndexOf(s, needle)Find the first (or last) occurrence of needle in s. The result is a byte offset, so it composes directly with substring's byte indexing. Returns Option.none when the needle does not occur.
| Signature | Description |
|---|---|
indexOf(String, String) → Option[Int] | Byte offset of the first occurrence. |
lastIndexOf(String, String) → Option[Int] | Byte offset of the last occurrence. |
indexOf("hello world", "world") unwrap -- 6
indexOf("hello", "xyz") isNone -- true
lastIndexOf("abcabc", "bc") unwrap -- 4
-- Composes with substring (both are byte-based)
let s = "key=value";
let i = s indexOf("=") unwrap;
s substring(i + 1, s length - i - 1) -- "value"
parseInt(s) / parseInt(s, radix) / parseFloat(s)Strict string-to-number parsing that can report failure (unlike the toInt/toFloat conversions, which only accept values that are already numbers). The whole string must be a valid number — no surrounding whitespace, no trailing characters. Returns Option.none on any malformed input, including integer overflow.
| Signature | Description |
|---|---|
parseInt(String) → Option[Int] | Parse a base-10 integer with optional sign. |
parseInt(String, Int) → Option[Int] | Parse in the given radix (2–36; digits beyond 9 are letters, case-insensitive). |
parseFloat(String) → Option[Float] | Parse a float; "inf"/"nan" and exponents accepted. |
parseInt("42") unwrap -- 42
parseInt("-17") unwrap -- -17
parseInt("12x") isNone -- true (trailing junk)
parseInt(" 12") isNone -- true (whitespace not skipped)
parseInt("ff", 16) unwrap -- 255
parseInt("101", 2) unwrap -- 5
parseFloat("3.5") unwrap -- 3.5
parseFloat("1e3") unwrap -- 1000.0
parseFloat("nope") unwrapOr(0.0) -- 0.0
codePoints(s)Returns a lazy List[Int] of Unicode code points decoded from the UTF-8 string. Each element is the integer value of a single code point. Because the result is a lazy list, it composes naturally with take, drop, map, filter, and other list operations without decoding the entire string up front.
| Signature | Description |
|---|---|
codePoints(String) → List[Int] | Lazy list of Unicode code points. |
codePoints("ABC") collect(3) -- [65, 66, 67]
codePoints("") isNil -- true
codePoints("Z") head -- 90
codePoints("\u00e9") head -- 233 (U+00E9, 2-byte UTF-8)
codePoints("\u20ac") head -- 8364 (U+20AC, 3-byte UTF-8)
codePoints("hello") take(3) collect(3) -- [104, 101, 108]
Strings support the [] indexing operator to access individual bytes. The index is zero-based and the result is an Int representing the byte value (0–255).
| Expression | Type | Description |
|---|---|---|
s[i] | Int | Byte value at index i. |
let s = "hello";
s[0] -- 104 (ASCII 'h')
s[1] -- 101 (ASCII 'e')
s[4] -- 111 (ASCII 'o')
toSymbol(s)Intern a string into a Symbol. The resulting symbol is the same interned value as the corresponding '-literal, so toSymbol("foo") == 'foo. Use this when the symbol name is only known at runtime (built from string operations) rather than written as a literal.
| Signature | Description |
|---|---|
toSymbol(String) → Symbol | Intern the string's text as a symbol. |
toSymbol("hello") println; -- hello
toSymbol("foo") == 'foo; -- true (same interned symbol)
toSymbol("note_" $ toString(3)); -- 'note_3 (name built at runtime)
↑ Back to top
The fmt function formats a string by substituting placeholders with values. It takes variadic arguments — any number of values of any type.
fmt(template, ...values)| Signature | Description |
|---|---|
fmt(String, ...args) → String | Format a string by replacing placeholders with the given values. |
| Placeholder | Description |
|---|---|
%^ | Positional — replaced by the next value in order (left to right). |
%0 – %9 | Indexed — replaced by the value at the given zero-based index. Can be repeated. |
%% | Literal percent sign. |
-- Positional placeholders
"%^ + %^ = %^" fmt(1, 2, 3) -- "1 + 2 = 3"
-- Indexed placeholders (zero-based)
"%0 and %2 and %1" fmt("a", "b", "c") -- "a and c and b"
-- Repeated index
"%0 %0 %0" fmt("echo") -- "echo echo echo"
-- Escape percent
"100%% done" fmt() -- "100% done"
"%%=%^" fmt(42) -- "%=42"
-- Works with any type
"half = %^" fmt(1/2) -- "half = 1/2"
"array: %^" fmt([10, 20, 30]) -- "array: [10, 20, 30]"
"list: %^" fmt(1::2::3::nil) -- "list: List(1, 2, 3)"
-- Pipeline style (idiomatic)
"hello %^!" fmt("world") println; -- hello world!
"%^ items" fmt(42) println; -- 42 items
-- Zero args when no placeholders
"no placeholders" fmt() -- "no placeholders"
↑ Back to top
Functions that operate on Range<Int> values.
| Function | Signature | Description |
|---|---|---|
length(r) | Range<Int> → Int | Number of elements in the range. Returns -1 for infinite ranges. |
isEmpty(r) | Range<Int> → Bool | True when the range has no elements. Infinite ranges are never empty. |
toArray(r) | Range<Int> → [Int] | Materialize the range into an array. |
toList(r) | Range<Int> → List<Int> | Create a lazy list from the range. Elements are generated on demand. |
let r = (1..5);
r length -- 5
r toArray -- [1, 2, 3, 4, 5]
r toList -- List(1, 2, 3, 4, 5) (lazy)
↑ Back to top
These functions are overloaded to work on both [T] and List<T>. Array versions are eager (return a new array); list versions are lazy (return a lazily-evaluated list). All functions support pipeline syntax: xs map(f) is equivalent to map(xs, f).
xs take(3) map(f) filter(g) is equivalent to filter(map(take(xs, 3), f), g).
length(collection)Returns the number of elements in the collection.
| Signature | Description |
|---|---|
length([T]) → Int | Number of elements in the array. |
length(List<T>) → Int | Number of elements in the list. Forces the entire list. |
length on a List forces every element. Calling it on an infinite list (e.g. from cyc or a range like (1..)) will never terminate.
[1, 2, 3, 4, 5] length -- 5
List(1, 2, 3) length -- 3
[10, 20, 30] length -- 3
isEmpty(collection)Returns true when the collection has no elements. Defined for every collection length covers — arrays, lists, maps, sets, strings, ranges, and persistent vectors/maps. Unlike length, isEmpty on a List answers in O(1) without forcing any elements (equivalent to isNil), so it is safe on infinite lists. An infinite range is never empty.
| Signature | Description |
|---|---|
isEmpty([T]) → Bool | True when the array has no elements. |
isEmpty(List<T>) → Bool | True when the list is nil. O(1); does not force. |
[Int]() isEmpty -- true
[1, 2, 3] isEmpty -- false
nil isEmpty -- true
(1..) isEmpty -- false (infinite, does not hang)
take(collection, n)Returns the first n elements.
| Signature | Description |
|---|---|
take([T], Int) → [T] | First n elements of an array. |
take(List<T>, Int) → List<T> | Lazily takes first n elements of a list. |
[1, 2, 3, 4, 5] take(3) -- [1, 2, 3]
List(1, 2, 3, 4, 5) take(3) -- List(1, 2, 3)
drop(collection, n)Skips the first n elements and returns the rest.
| Signature | Description |
|---|---|
drop([T], Int) → [T] | All but the first n elements of an array. |
drop(List<T>, Int) → List<T> | Eagerly skips n elements, returns the rest of the list. |
[1, 2, 3, 4, 5] drop(2) -- [3, 4, 5]
List(1, 2, 3, 4, 5) drop(2) -- List(3, 4, 5)
takeWhile(collection, predicate)Returns elements from the front while the predicate holds.
| Signature | Description |
|---|---|
takeWhile([T], (T) → Bool) → [T] | Eagerly takes elements while predicate is true. |
takeWhile(List<T>, (T) → Bool) → List<T> | Lazily takes elements while predicate is true. |
[1, 2, 3, 4, 5] takeWhile(fn(x Int) { x < 4 }) -- [1, 2, 3]
dropWhile(collection, predicate)Drops elements from the front while the predicate holds, returns the rest.
| Signature | Description |
|---|---|
dropWhile([T], (T) → Bool) → [T] | Eagerly drops elements while predicate is true. |
dropWhile(List<T>, (T) → Bool) → List<T> | Lazily drops elements while predicate is true. |
[1, 2, 3, 4, 5] dropWhile(fn(x Int) { x < 4 }) -- [4, 5]
stride(collection, n)Takes every nth element, starting from the first.
| Signature | Description |
|---|---|
stride([T], Int) → [T] | Every nth element of an array. |
stride(List<T>, Int) → List<T> | Lazily takes every nth element of a list. |
[1, 2, 3, 4, 5, 6, 7] stride(2) -- [1, 3, 5, 7]
[1, 2, 3, 4, 5, 6, 7, 8, 9] stride(3) -- [1, 4, 7]
stutter(collection, n), stutter(array, counts)Repeats each element n times. The counts overload replicates element i counts[i] times; the counts array is indexed cyclically (like ordinary array indexing), so a shorter counts array tiles across the source, and counts <= 0 drop the element.
| Signature | Description |
|---|---|
stutter([T], Int) → [T] | Repeat each element n times in an array. |
stutter(List<T>, Int) → List<T> | Lazily repeats each element n times. |
stutter([T], [Int]) → [T] | Per-element replication counts. |
[1, 2, 3] stutter(2) -- [1, 1, 2, 2, 3, 3]
[10, 20, 30] stutter([1, 0, 2]) -- [10, 30, 30]
[7, 8] stutter([3]) -- [7, 7, 7, 8, 8, 8]
repeat(value, n)Creates an array containing value repeated n times.
| Signature | Description |
|---|---|
repeat(T, Int) → [T] | Returns an array of n copies of the value. Works with any type. |
repeat(0, 5) -- [0, 0, 0, 0, 0]
repeat(3.14, 3) -- [3.14, 3.14, 3.14]
repeat("hello", 2) -- [hello, hello]
repeat(true, 4) -- [true, true, true, true]
repeat(42, 0) -- []
map(collection, fn)Applies a function to each element, returning a new collection of the results.
| Signature | Description |
|---|---|
map([T], (T) → U) → [U] | Eagerly maps over an array. |
map(List<T>, (T) → U) → List<U> | Lazily maps over a list. |
[1, 2, 3] map(fn(x Int) { x * x }) -- [1, 4, 9]
[1, 2, 3] map(fn(x Int) { x * 2 }) -- [2, 4, 6]
List(1, 2, 3) map(fn(x Int) { x + 10 }) -- List(11, 12, 13)
filter(collection, predicate)Returns elements that satisfy the predicate.
| Signature | Description |
|---|---|
filter([T], (T) → Bool) → [T] | Eagerly filters an array. |
filter(List<T>, (T) → Bool) → List<T> | Lazily filters a list. |
[1, 2, 3, 4, 5] filter(fn(x Int) { x > 2 }) -- [3, 4, 5]
[1, 2, 3, 4, 5] filter(fn(x Int) { x % 2 == 0 }) -- [2, 4]
zip(a, b)Combines two collections element-wise into a collection of tuples. Result length is the shorter of the two inputs.
| Signature | Description |
|---|---|
zip([T], [U]) → [(T, U)] | Eagerly zips two arrays into an array of tuples. |
zip(List<T>, List<U>) → List<(T, U)> | Lazily zips two lists into a list of tuples. |
zip([1, 2, 3], [10, 20, 30]) -- [(1, 10), (2, 20), (3, 30)]
zip(["a", "b"], [1, 2]) -- [("a", 1), ("b", 2)]
enumerate(collection)Pairs each element with its zero-based index.
| Signature | Description |
|---|---|
enumerate([T]) → [(Int, T)] | Eagerly enumerates an array. |
enumerate(List<T>) → List<(Int, T)> | Lazily enumerates a list. |
["a", "b", "c"] enumerate -- [(0, "a"), (1, "b"), (2, "c")]
[10, 20, 30] enumerate -- [(0, 10), (1, 20), (2, 30)]
fold(collection, init, fn)Left fold (reduce) with an initial accumulator value.
| Signature | Description |
|---|---|
fold([T], U, (U, T) → U) → U | Fold over an array. |
fold(List<T>, U, (U, T) → U) → U | Fold over a list (eager — forces the entire list). |
[1, 2, 3, 4, 5] fold(0, fn(acc Int, x Int) { acc + x }) -- 15
["a", "b", "c"] fold("", fn(s String, x String) { s $ x }) -- "abc"
scan(collection, init, fn)Like fold, but returns all intermediate accumulator values. The result has one more element than the input (starts with init).
| Signature | Description |
|---|---|
scan([T], U, (U, T) → U) → [U] | Eagerly scans an array. |
scan(List<T>, U, (U, T) → U) → List<U> | Lazily scans a list. |
[1, 2, 3, 4, 5] scan(0, fn(a Int, x Int) { a + x })
-- [0, 1, 3, 6, 10, 15] (running sum)
fold1(collection, fn)Left fold using the first element as the initial accumulator. The collection must be non-empty.
| Signature | Description |
|---|---|
fold1([T], (T, T) → T) → T | Fold over an array using first element as init. |
fold1(List<T>, (T, T) → T) → T | Fold over a list using first element as init. |
[1, 2, 3, 4, 5] fold1(fn(a Int, b Int) { a + b }) -- 15
[3, 1, 4, 1, 5] fold1(fn(a Int, b Int) { max(a, b) }) -- 5
scan1(collection, fn)Like fold1, but returns all intermediate accumulator values. The result has the same length as the input.
| Signature | Description |
|---|---|
scan1([T], (T, T) → T) → [T] | Eagerly scans an array. |
scan1(List<T>, (T, T) → T) → List<T> | Lazily scans a list. |
[1, 2, 3, 4, 5] scan1(fn(a Int, b Int) { a + b })
-- [1, 3, 6, 10, 15] (running sum without init)
find(collection, predicate)Returns the index of the first element satisfying the predicate, or -1 if not found.
| Signature | Description |
|---|---|
find([T], (T) → Bool) → Int | Index of first match in an array. |
find(List<T>, (T) → Bool) → Int | Index of first match in a list (forces elements until found). |
[10, 20, 30, 40] find(fn(x Int) { x > 25 }) -- 2 (index of 30)
[1, 2, 3] find(fn(x Int) { x > 10 }) -- -1 (not found)
cat(a, b)Concatenates two collections of the same type.
| Signature | Description |
|---|---|
cat([T], [T]) → [T] | Concatenate two arrays. |
cat(List<T>, List<T>) → List<T> | Lazily concatenate two lists. |
cat([1, 2, 3], [4, 5, 6]) -- [1, 2, 3, 4, 5, 6]
cat(List(1, 2), List(3, 4)) -- List(1, 2, 3, 4)
join(collection)Flattens one level of nesting. Given a collection of collections, returns a single flat collection. For String elements — strings being sequences of characters — one-level flattening means concatenation; a separator overload exists for the array form as a convenience. The String forms only apply when the element type is String, so they never hide a nested-collection flatten.
| Signature | Description |
|---|---|
join([[T]]) → [T] | Flatten an array of arrays. |
join(List<List<T>>) → List<T> | Lazily flatten a list of lists. |
join([String]) → String, join(List<String>) → String | Concatenate strings. |
join([String], String) → String, join(List<String>, String) → String | Concatenate with a separator between elements. |
[[1, 2], [3, 4], [5]] join -- [1, 2, 3, 4, 5]
List(List(1, 2), List(3, 4)) join -- List(1, 2, 3, 4)
["ab", "cd"] join -- "abcd"
["a", "b"] join(", ") -- "a, b"
flatten(collection)Recursively flattens all nesting levels of the same container type. Unlike join which removes only one level, flatten removes all levels of Array (or List) nesting until the element type is no longer the same container type.
| Signature | Description |
|---|---|
flatten([[...[T]...]]) → [T] | Recursively flatten all Array nesting levels. |
flatten(List<..List<T>..>) → List<T> | Lazily flatten all List nesting levels. |
[[1, 2], [3, 4]] flatten -- [1, 2, 3, 4] (same as join)
[[[1, 2], [3]], [[4, 5, 6]]] flatten -- [1, 2, 3, 4, 5, 6] (all levels)
[[[List(1, 2)], [List(3)]]] flatten -- [List(1, 2), List(3)] (stops at List)
flatten only removes layers of the same container type. A [[List<Int>]] flattens to [List<Int>] — the array layers are removed but the List is preserved.
sum(collection), product(collection), mean(collection)Numeric reductions over Int, Float, Fraction, or Complex elements; the result has the element type. sum of an empty collection is 0, product is 1, and mean is nan. mean is Int/Float only and always returns Float.
| Signature | Description |
|---|---|
sum([T]) → T for T in Int/Float/Fraction/Complex | Sum of the elements. Also for the List forms. |
product([T]) → T, same element types | Product of the elements. Also for lists. |
mean([Int]) → Float, mean([Float]) → Float | Arithmetic mean. Also for lists. |
[1, 2, 3, 4] sum -- 10
[1/2, 1/3, 1/6] sum -- 1/1
(1..5) toList product -- 120
[1.0, 2.0, 6.0] mean -- 3.0
min(collection), max(collection)Smallest / largest element of an array or list. Works for Int, Float, Fraction, and String elements (the two-arg scalar forms min(a, b) / max(a, b) are documented in the math section). Empty collections yield the reduction identity: INT64_MAX/INT64_MIN for Int and Fraction, ±inf for Float, "" for String.
| Signature | Description |
|---|---|
min([T]) → T for T in Int/Float/Fraction/String | Minimum element. Also for lists. |
max([T]) → T, same element types | Maximum element. Also for lists. |
[3, 1, 4, 1, 5] min -- 1
[3, 1, 4, 1, 5] max -- 5
["banana", "apple"] min -- "apple"
sums(collection), products(collection), mins(collection), maxs(collection)Running (cumulative) reductions: element i of the result is the reduction of elements 0..i, so the result has the same length as the input. The List forms are lazy and compose with infinite lists.
| Signature | Description |
|---|---|
sums([T]) → [T] for T in Int/Float/Fraction/Complex | Running sum. Also for lists (lazy). |
products(...) | Running product; same shapes. |
mins(...), maxs(...) | Running minimum / maximum; Int/Float/Fraction (Complex is unordered). |
[1, 2, 3, 4] sums -- [1, 3, 6, 10]
[3, 1, 4, 1, 5] mins -- [3, 1, 1, 1, 1]
(1..) toList sums take(5) -- List(1, 3, 6, 10, 15)
any(collection, fn), all(collection, fn)Predicate quantifiers, short-circuiting (lazy lists are only forced as far as needed). any of an empty collection is false; all is true. Without a predicate they reduce a Bool collection directly.
| Signature | Description |
|---|---|
any([T], (T) Bool) → Bool | True if the predicate holds for some element. Also for lists. |
all([T], (T) Bool) → Bool | True if the predicate holds for every element. Also for lists. |
any([Bool]) → Bool, all([Bool]) → Bool | Reduce a Bool collection by or / and. Also for lists. |
[1, 2, 3] any(fn(x Int) { x > 2 }) -- true
[1, 2, 3] all(fn(x Int) { x > 2 }) -- false
[true, false] any -- true
contains(collection, x)Membership test for arrays and lists (in addition to the String/Set/Map forms documented in their own sections). Uses element equality, so it works for strings, tuples, and other composite element types.
| Signature | Description |
|---|---|
contains([T], T) → Bool | True if some element equals x. |
contains(List<T>, T) → Bool | List form; forces lazy elements only until a match. |
[1, 2, 3] contains(2) -- true
List((1, 2), (3, 4)) contains((3, 4)) -- true
clump(array, n)Groups an array into rows of n elements; a short remainder row is kept. n <= 0 yields an empty array.
| Signature | Description |
|---|---|
clump([T], Int) → [[T]] | Fixed-size grouping. |
(1..10) toArray clump(3) -- [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
toSet(collection)Builds a Set from the elements of an array or list, discarding duplicates.
| Signature | Description |
|---|---|
toSet([T]) → Set<T> | Array form. |
toSet(List<T>) → Set<T> | List form (forces the whole list). |
[1, 2, 2, 3, 1] toSet length -- 3
fromCodePoints(collection)The inverse of codePoints: builds a String from Unicode code points (UTF-8 encoded). Invalid code points become U+FFFD.
| Signature | Description |
|---|---|
fromCodePoints([Int]) → String | Array form. |
fromCodePoints(List<Int>) → String | List form. |
[72, 105, 33] fromCodePoints -- "Hi!"
"héllo" codePoints fromCodePoints -- "héllo"
↑ Back to top
These functions operate exclusively on [T]. Functions ending in ! mutate the array in place; functions without ! return a new array and leave the input untouched.
reverse(array)Returns a new array with elements in reverse order.
| Signature | Description |
|---|---|
reverse([T]) → [T] | Reverse an array (returns a new array). |
[1, 2, 3, 4, 5] reverse -- [5, 4, 3, 2, 1]
[1, 2, 3] reverse -- [3, 2, 1]
push(array, element)Returns a new array with the element appended at the end. The original array is unchanged.
| Signature | Description |
|---|---|
push([T], T) → [T] | Append an element to an array (returns a new array). |
[1, 2, 3] push(4) -- [1, 2, 3, 4]
pop(array)Returns a new array with the last element removed. The original array is unchanged.
| Signature | Description |
|---|---|
pop([T]) → [T] | Remove the last element of an array (returns a new array). |
[1, 2, 3, 4] pop -- [1, 2, 3]
[1, 2, 3] pop -- [1, 2]
a[i] = xIn-place write to a single array slot. Indices wrap cyclically — a[-1] = x writes the last element, a[n] = x when n ≥ length wraps via i mod length. This matches the existing read semantics of a[i]. Writing through any alias affects all aliases of the same array.
var a = [1, 2, 3, 4, 5];
a[0] = 100;
a[-1] = 999;
a println; -- [100, 2, 3, 4, 999]
at(array, index)Element read as an ordinary function — a at(i) is exactly a[i], cyclic index included. With an array of indices it gathers, mirroring a[[i1, i2, …]]. Together with put! below, this lets generic code use one protocol over arrays and user indexable types (see Indexable Objects in Tzopilotl by Example).
| Signature | Description |
|---|---|
at([T], Int) → T | Element at cyclic index (negative wraps from the end). |
at([T], [Int]) → [T] | Gather: new array of the elements at each index. |
let a = [10, 20, 30];
a at(1) println; -- 20
a at(-1) println; -- 30
a at([2, 0, 0]) println; -- [30, 10, 10]
put!(array, index, value)Element write as an ordinary function — a put!(i, v) is exactly a[i] = v, cyclic index included. Returns the same array for chaining.
| Signature | Description |
|---|---|
put!([T], Int, T) → [T] | Write element at cyclic index in place. Returns the same array. |
var a = [1, 2, 3];
a put!(1, 99);
a put!(-1, 30) println; -- [1, 99, 30]
push!(array, element)Mutating append. Adds the element to the end of this array in place and returns the array itself, allowing chained calls.
| Signature | Description |
|---|---|
push!([T], T) → [T] | Append an element in place. Returns the same array. |
var a = [1, 2, 3];
a push!(4);
a push!(5) push!(6);
a println; -- [1, 2, 3, 4, 5, 6]
pop!(array)Mutating pop. Removes the last element from the array in place and returns it. Behavior on an empty array is undefined.
| Signature | Description |
|---|---|
pop!([T]) → T | Remove and return the last element (mutates the array). |
var a = [1, 2, 3, 4];
let last = a pop!;
last println; -- 4
a println; -- [1, 2, 3]
clear!(array)Mutating clear. Removes every element in place. Returns the same array for chaining. Also defined for maps and sets (see the Map and Set sections).
| Signature | Description |
|---|---|
clear!([T]) → [T] | Remove every element (mutates the array). Returns the same array. |
var a = [1, 2, 3];
a clear!;
a println; -- []
append!(array, source)Mutating bulk append — the in-place analogue of $ concatenation. Appends every element of the source (an array or a list of the same element type) to the array. Returns the same array for chaining. A list source is forced as it is walked, so an infinite list will not terminate. Self-append (a append!(a)) is safe and doubles the array.
| Signature | Description |
|---|---|
append!([T], [T]) → [T] | Append every element of the source array (mutates the first array). Returns the same array. |
append!([T], List<T>) → [T] | Append every element of the list, forcing it. |
var a = [1, 2];
a append!([3, 4]);
a println; -- [1, 2, 3, 4]
a append!(List(5, 6));
a println; -- [1, 2, 3, 4, 5, 6]
a clear! append!([9]); -- replace contents in place
a println; -- [9]
sort(array)Returns a new array sorted in ascending order.
| Signature | Description |
|---|---|
sort([Int]) → [Int] | Sort integers ascending. |
sort([Float]) → [Float] | Sort floats ascending. |
sort([String]) → [String] | Sort strings lexicographically. |
[3, 1, 4, 1, 5, 9, 2, 6] sort -- [1, 1, 2, 3, 4, 5, 6, 9]
[5, 3, 1, 4, 2] sort -- [1, 2, 3, 4, 5]
muss(array)Returns a new array with elements in a scrambled (pseudo-random) order. Uses a deterministic shuffle based on array content.
| Signature | Description |
|---|---|
muss([T]) → [T] | Scramble an array. |
[1, 2, 3, 4, 5] muss -- e.g. [3, 5, 1, 4, 2]
copy(array)Returns a shallow copy of the array. Use this when you need to mutate one alias without affecting another — arrays are passed by reference, so plain assignment (var b = a;) does not create an independent copy. Nested Obj* elements are shared, not deep-copied.
| Signature | Description |
|---|---|
copy([T]) → [T] | Shallow copy of an array. |
var a = [1, 2, 3];
var b = a copy;
a push!(4);
a println; -- [1, 2, 3, 4]
b println; -- [1, 2, 3] (b is independent)
↑ Back to top
These functions operate exclusively on List<T>.
head(list)Returns the first element of the list. Behavior is undefined on a nil list.
| Signature | Description |
|---|---|
head(List<T>) → T | First element of the list. |
List(1, 2, 3) head -- 1
List(42) head -- 42
tail(list)Returns the list without its first element. Returns nil if the list has only one element. Behavior is undefined on a nil list.
| Signature | Description |
|---|---|
tail(List<T>) → List<T> | All elements after the first. |
List(1, 2, 3) tail -- List(2, 3)
List(42) tail -- nil
cons(element, list)Prepends an element to the front of a list, returning a new list. The list may be nil.
| Signature | Description |
|---|---|
cons(T, List<T>) → List<T> | Prepend an element to a list. |
cons(0, List(1, 2, 3)) -- List(0, 1, 2, 3)
let empty List<Int> = nil;
cons(1, empty) -- List(1)
:: (cons) operator provides equivalent functionality with infix syntax: 0 :: List(1, 2, 3).
isNil(list) / notNil(list)Test whether a list is empty (nil) or non-empty.
| Signature | Description |
|---|---|
isNil(List<T>) → Bool | Returns true if the list is nil. |
notNil(List<T>) → Bool | Returns true if the list is not nil. |
let xs = List(1, 2, 3);
let empty List<Int> = nil;
isNil(xs) -- false
isNil(empty) -- true
notNil(xs) -- true
notNil(empty) -- false
cyc(list)Returns an infinite list that cycles through the elements of the input list repeatedly.
| Signature | Description |
|---|---|
cyc(List<T>) → List<T> | Infinite cycle of a list. |
List(1, 2, 3) cyc take(10) -- List(1, 2, 3, 1, 2, 3, 1, 2, 3, 1)
List(1, 2, 3) cyc take(7) -- List(1, 2, 3, 1, 2, 3, 1)
ncyc(collection, n)Returns the input repeated n times. Works on both lists and arrays (unlike cyc, whose infinite result only makes sense as a lazy list).
| Signature | Description |
|---|---|
ncyc(List<T>, Int) → List<T> | Cycle a list n times. |
ncyc([T], Int) → [T] | Cycle an array n times. |
List(1, 2, 3) ncyc(3) -- List(1, 2, 3, 1, 2, 3, 1, 2, 3)
[1, 2] ncyc(4) -- [1, 2, 1, 2, 1, 2, 1, 2]
hang(list)Returns an infinite list that, upon reaching the last element, repeats it indefinitely.
| Signature | Description |
|---|---|
hang(List<T>) → List<T> | Hang on the last element forever. |
List(1, 2, 3) hang take(8) -- List(1, 2, 3, 3, 3, 3, 3, 3)
List(10, 20) hang take(5) -- List(10, 20, 20, 20, 20)
iter(value, fn)Returns an infinite list of repeated applications of fn to value: value, fn(value), fn(fn(value)), …
| Signature | Description |
|---|---|
iter(T, (T) → T) → List<T> | Infinite iterated function application. |
iter(1, fn(x Int) Int { x * 2 }) take(10)
-- List(1, 2, 4, 8, 16, 32, 64, 128, 256, 512)
iter(0, fn(x Int) Int { x + 1 }) take(5)
-- List(0, 1, 2, 3, 4)
↑ Back to top
Functions that operate on [K: V] values. Maps are heap-allocated hash maps passed by reference. The functions without a trailing ! (put, remove, merge, …) return new maps and leave their inputs untouched. The bang-suffixed variants put! and remove! mutate in place; m[key] = value is equivalent to put!. Map literals use [key: value] syntax.
get(map, key) / get(map, key, default)Retrieves the value for a key. The two-argument form returns Option<V> — Option.some(value) if found, Option.none if missing. The three-argument form returns the value directly, using the provided default if the key is missing.
| Signature | Description |
|---|---|
get([K: V], K) → Option<V> | Get value for key; returns Option.some(v) or Option.none. |
get([K: V], K, V) → V | Get value for key; returns default if missing. |
let m = ["a": 1, "b": 2, "c": 3];
m get("b") println; -- Option<Int>.some(2)
m get("z") println; -- Option<Int>.none
m get("b") unwrap println; -- 2
m get("z", 99) println; -- 99 (not found, returns default)
Map subscript syntax also returns Option<V>:
m["b"] println; -- Option<Int>.some(2)
m["z"] println; -- Option<Int>.none
m["b"] unwrap println; -- 2
m["z"] unwrapOr(99) println; -- 99
getOrDefault(map, key, default)Returns the value for the key, or default if the key is missing. Identical in behavior to the three-argument get; provided as a more descriptive name. The default is evaluated eagerly — if computing it is expensive or should only happen on a miss, use getOrElse instead.
| Signature | Description |
|---|---|
getOrDefault([K: V], K, V) → V | Value for key, or the given default if missing. |
let m = ["a": 1, "b": 2];
m getOrDefault("a", 0) println; -- 1
m getOrDefault("z", 0) println; -- 0
getOrElse(map, key, fallback)Returns the value for the key, or the result of calling fallback with the key if it is missing. The fallback is a function (K) → V and runs only on a miss (lazy), so use it when the default depends on the key or is costly to compute.
| Signature | Description |
|---|---|
getOrElse([K: V], K, (K) → V) → V | Value for key, or fallback(key) if missing (fallback called lazily). |
let m = ["a": 1, "b": 2];
m getOrElse("b", fn(k String) Int { 0 }) println; -- 2 (fallback not called)
m getOrElse("missing", fn(k String) Int { k length }) println; -- 7
m[key] = valueInsert-or-update on a map in place. If the key already exists, its value is replaced; otherwise a new entry is added.
var m = ["a": 1];
m["b"] = 2; -- insert
m["a"] = 99; -- update existing
m println; -- [a: 99, b: 2]
put(map, key, value)Returns a new map with the key-value pair added or updated. The input map is unchanged. For in-place writes, prefer m[key] = value.
| Signature | Description |
|---|---|
put([K: V], K, V) → [K: V] | Add or update a key-value pair (returns a new map). |
let m = ["a": 1];
let m2 = m put("b", 2);
m2 println; -- [a: 1, b: 2]
put!(map, key, value)Adds or updates the key-value pair in place and returns the same map (for chaining). Equivalent to m[key] = value.
| Signature | Description |
|---|---|
put!([K: V], K, V) → [K: V] | Add or update a key-value pair in place. Returns the same map. |
var m = ["a": 1];
m put!("b", 2);
m put!("a", 99) put!("c", 3); -- chains; mutates m each time
m length println; -- 3
remove(map, key)Returns a new map with the given key removed.
| Signature | Description |
|---|---|
remove([K: V], K) → [K: V] | Remove a key from the map. |
remove!(map, key)Removes the given key in place and returns the same map (for chaining). Removing an absent key is a no-op.
| Signature | Description |
|---|---|
remove!([K: V], K) → [K: V] | Remove a key in place. Returns the same map. |
contains(map, key)Returns true if the key exists in the map.
| Signature | Description |
|---|---|
contains([K: V], K) → Bool | Check if key exists. |
let m = ["a": 1, "b": 2];
m contains("a") println; -- true
m contains("z") println; -- false
keys(map)Returns an array of all keys in the map.
| Signature | Description |
|---|---|
keys([K: V]) → [K] | Get all keys. |
values(map)Returns an array of all values in the map.
| Signature | Description |
|---|---|
values([K: V]) → [V] | Get all values. |
let m = ["x": 10, "y": 20];
m keys println; -- ["x", "y"]
m values println; -- [10, 20]
pairs(map)Returns an array of (key, value) tuples from the map.
| Signature | Description |
|---|---|
pairs([K: V]) → [(K, V)] | Get all key-value pairs as tuples. |
let m = ["a": 1, "b": 2, "c": 3];
m pairs println; -- [(a, 1), (b, 2), (c, 3)]
merge(map1, map2)Returns a new map containing all key-value pairs from both maps. Values from the second map override those in the first for duplicate keys.
| Signature | Description |
|---|---|
merge([K: V], [K: V]) → [K: V] | Merge two maps (second wins on conflicts). |
let a = ["x": 1, "y": 2];
let b = ["y": 99, "z": 3];
merge(a, b) println; -- [x: 1, y: 99, z: 3]
mergeIfAbsent(map1, map2)Returns a new map: a copy of map1 with entries from map2 added only for keys that are not already in map1. Existing keys keep map1's values. Both inputs are unchanged.
| Signature | Description |
|---|---|
mergeIfAbsent([K: V], [K: V]) → [K: V] | Add only the keys missing from the first map. |
let a = ["x": 1, "y": 2];
let b = ["y": 99, "z": 3];
mergeIfAbsent(a, b) println; -- [x: 1, y: 2, z: 3]
mergeIfPresent(map1, map2)Returns a new map: a copy of map1 with values overwritten from map2 only for keys that already exist in map1. Keys unique to map2 are ignored. Both inputs are unchanged.
| Signature | Description |
|---|---|
mergeIfPresent([K: V], [K: V]) → [K: V] | Overwrite only the keys shared with the first map. |
let a = ["x": 1, "y": 2];
let b = ["y": 99, "z": 3];
mergeIfPresent(a, b) println; -- [x: 1, y: 99]
length(map) / isEmpty(map)Returns the number of key-value pairs in the map, or whether there are none.
| Signature | Description |
|---|---|
length([K: V]) → Int | Number of entries in the map. |
isEmpty([K: V]) → Bool | True when the map has no entries. |
clear!(map)Mutating clear. Removes every entry in place. Returns the same map for chaining.
| Signature | Description |
|---|---|
clear!([K: V]) → [K: V] | Remove every entry (mutates the map). Returns the same map. |
copy(map)Returns a shallow copy of the map. Use when an alias needs to be mutated independently. Nested Obj* keys and values are shared with the original.
| Signature | Description |
|---|---|
copy([K: V]) → [K: V] | Shallow copy of a map. |
Functions that operate on Option<T> values. Option<T> is a built-in template enum with cases some T and none. It is returned by map subscript (map[key]) and get(map, key) to safely handle missing keys.
unwrap(option)Extracts the value from a some. Halts with an error if the option is none.
| Signature | Description |
|---|---|
unwrap(Option<T>) → T | Extract the value; halts on none. |
let m = ["a": 1, "b": 2];
m["a"] unwrap println; -- 1
-- m["z"] unwrap println; -- would halt: unwrap called on none
unwrapOr(option, default)Extracts the value from a some, or returns the default value if none.
| Signature | Description |
|---|---|
unwrapOr(Option<T>, T) → T | Extract the value or use default. |
let m = ["a": 1, "b": 2];
m["a"] unwrapOr(99) println; -- 1
m["z"] unwrapOr(99) println; -- 99
isSome(option)Returns true if the option contains a value.
| Signature | Description |
|---|---|
isSome(Option<T>) → Bool | Check if option has a value. |
let m = ["a": 1];
m["a"] isSome println; -- true
m["z"] isSome println; -- false
isNone(option)Returns true if the option is empty (no value).
| Signature | Description |
|---|---|
isNone(Option<T>) → Bool | Check if option is empty. |
let m = ["a": 1];
m["a"] isNone println; -- false
m["z"] isNone println; -- true
↑ Back to top
Functions for creating, reading, and writing mutable references. These are the functional equivalents of the &, *, and <- operators, and unlike operators they participate in automapping.
ref(value)Creates a new mutable reference containing the given value.
| Signature | Description |
|---|---|
ref(T) → Ref<T> | Create a mutable reference to a value. |
let x = ref(42); -- Ref<Int>
let y = ref(3.14); -- Ref<Float>
let s = ref("hello"); -- Ref<String>
-- Automap: create refs from an array
let refs = [1, 2, 3] ref; -- [Ref<Int>]
deref(ref)Reads the current value from a mutable reference.
| Signature | Description |
|---|---|
deref(Ref<T>) → T | Read the value from a reference. |
let x = ref(42);
deref(x) println; -- 42
x deref println; -- 42 (postfix)
-- Automap: deref an array of refs
let refs = [ref(1), ref(2), ref(3)];
refs deref println; -- [1, 2, 3]
setref(value, ref)Writes a new value into a mutable reference. Returns the written value.
| Signature | Description |
|---|---|
setref(T, Ref<T>) → T | Write a value into a reference; returns the value. |
let x = ref(0);
setref(42, x);
x deref println; -- 42
-- Postfix style
99 setref(x);
x deref println; -- 99
-- Automap: set all refs in an array
let refs = [ref(1), ref(2), ref(3)];
setref(0, refs);
refs deref println; -- [0, 0, 0]
↑ Back to top
Functions for working with the Any type. Any wraps a value of any type into a uniform runtime object, enabling heterogeneous collections and dynamic type dispatch.
any(value)Wraps a single value of any type into an Any object.
| Signature | Description |
|---|---|
any(T) → Any | Wrap a value of any type into Any. |
any(5) println; -- Any(5, Int)
any("hello") println; -- Any(hello, String)
any(3.14) println; -- Any(3.14, Float)
any(true) println; -- Any(true, Bool)
any(v1, v2, ...)Wraps multiple values and returns a [Any].
| Signature | Description |
|---|---|
any(T1, T2, ...) → [Any] | Wrap each argument into Any and return as an array. |
any(1, "two", 3.0) println;
-- [Any(1, Int), Any(two, String), Any(3.0, Float)]
-- Nested calls work
any(1, any(2, 3)) println;
-- [Any(1, Int), Any([Any(2, Int), Any(3, Int)], [Any])]
toAnyArrayConverts a tuple to a [Any], wrapping each element.
| Signature | Description |
|---|---|
toAnyArray(Tuple) → [Any] | Convert a tuple to a heterogeneous Any array. |
(1, "two", 'three, 4.0) toAnyArray println;
-- [Any(1, Int), Any(two, String), Any('three, Symbol), Any(4.0, Float)]
as(Type)Postfix type-test operator on Any values. Returns Option<T> — some(value) if the wrapped type matches, none otherwise.
| Signature | Description |
|---|---|
Any as(T) → Option<T> | Test and unwrap the Any value to the given type. |
let a = any(5);
a as(Int) println; -- Option<Int>.some(5)
a as(String) println; -- Option<String>.none
↑ Back to top
Functions for working with coroutines. A coroutine is declared with coro fn and produces a Coroutine<T> value that lazily yields elements of type T. See the Coroutines guide for full language details.
next(coroutine)Resumes the coroutine and returns the next yielded value wrapped in Option<T>. Returns none when the coroutine is exhausted.
| Signature | Description |
|---|---|
next(Coroutine<T>) → Option<T> | Resume and get the next value. |
coro fn count(n Int) Int {
var i = 0;
while (i < n) {
yield i;
i = i + 1;
}
}
let c = count(3);
c next println; -- Option<Int>.some(0)
c next println; -- Option<Int>.some(1)
c next println; -- Option<Int>.some(2)
c next println; -- Option<Int>.none
yield(value)Suspends the coroutine and produces a value. Can only be used inside a coro fn body. Supports both call and pipeline syntax.
| Signature | Description |
|---|---|
yield(T) → Void | Suspend and produce a value. |
coro fn example() Int {
yield 1; -- prefix form
2 yield; -- pipeline form
yield(3); -- explicit call form
}
yieldAll(coroutine)Delegates to another coroutine, yielding all of its values. Can only be used inside a coro fn body. The inner coroutine must have the same yield type.
| Signature | Description |
|---|---|
yieldAll(Coroutine<T>) → Void | Yield all values from another coroutine. |
coro fn inner() Int {
yield 10;
yield 20;
}
coro fn outer() Int {
yield 1;
yieldAll(inner()); -- yields 10, 20
yield 99;
}
-- outer() yields: 1, 10, 20, 99
toList(coroutine)Converts a coroutine into a lazy List<T>. The coroutine is resumed on demand as list elements are accessed, so this works with infinite coroutines when combined with lazy list operations like take.
| Signature | Description |
|---|---|
toList(Coroutine<T>) → List<T> | Convert coroutine to a lazy list. |
-- Finite coroutine
count(5) toList println; -- List(0, 1, 2, 3, 4)
-- Empty coroutine
count(0) toList println; -- nil
-- Infinite coroutine with take
coro fn fibs() Int {
var a = 0;
var b = 1;
while (true) {
yield a;
let tmp = a + b;
a = b;
b = tmp;
}
}
fibs() toList take(8) println; -- List(0, 1, 1, 2, 3, 5, 8, 13)
-- Chain with other list operations
count(5) toList head println; -- 0
count(5) toList drop(3) println; -- List(3, 4)
fibs() toList collect(6) println; -- [0, 1, 1, 2, 3, 5]
↑ Back to top
Functions that operate on Set<T> values. Sets are heap-allocated hash sets passed by reference. The functions without a trailing ! (add, remove, union, …) return new sets and leave their inputs untouched. insert!, remove!, and pop! mutate in place. Sets are constructed with Set(elem1, elem2, ...).
add(set, element)Returns a new set with the element added. The input set is unchanged.
| Signature | Description |
|---|---|
add(Set<T>, T) → Set<T> | Add an element to the set (returns a new set). |
remove(set, element)Returns a new set with the element removed. The input set is unchanged.
| Signature | Description |
|---|---|
remove(Set<T>, T) → Set<T> | Remove an element from the set (returns a new set). |
remove!(set, element)Mutating remove. Removes the element from this set in place; a no-op if it was not present. Returns the same set, allowing chained calls.
| Signature | Description |
|---|---|
remove!(Set<T>, T) → Set<T> | Remove an element in place. Returns the same set. |
insert!(set, element)Mutating insert. Adds the element to this set in place; a no-op if it was already present. Returns the same set, allowing chained calls.
| Signature | Description |
|---|---|
insert!(Set<T>, T) → Set<T> | Insert an element in place. Returns the same set. |
var s = Set(1, 2, 3);
s insert!(4);
s insert!(3); -- duplicate; no-op
s length println; -- 4
pop!(set)Mutating pop. Removes and returns one arbitrary element from the set. The iteration order isn't part of the contract; this is useful for “process the set element by element” patterns. Behavior on an empty set is undefined.
| Signature | Description |
|---|---|
pop!(Set<T>) → T | Remove and return one element (mutates the set). |
var s = Set(1, 2, 3);
let e = s pop!;
s length println; -- 2
s contains(e) println; -- false
contains(set, element)Returns true if the element exists in the set.
| Signature | Description |
|---|---|
contains(Set<T>, T) → Bool | Check if element exists. |
let s = Set(1, 2, 3);
s contains(2) println; -- true
s contains(5) println; -- false
union(set1, set2)Returns a set containing all elements from both sets.
| Signature | Description |
|---|---|
union(Set<T>, Set<T>) → Set<T> | Set union. |
intersection(set1, set2)Returns a set containing only elements present in both sets.
| Signature | Description |
|---|---|
intersection(Set<T>, Set<T>) → Set<T> | Set intersection. |
difference(set1, set2)Returns a set containing elements in the first set but not in the second.
| Signature | Description |
|---|---|
difference(Set<T>, Set<T>) → Set<T> | Set difference. |
let a = Set(1, 2, 3, 4);
let b = Set(3, 4, 5, 6);
union(a, b) println; -- Set(1, 2, 3, 4, 5, 6)
intersection(a, b) println; -- Set(3, 4)
difference(a, b) println; -- Set(1, 2)
toArray(set)Converts the set to an array of its elements.
| Signature | Description |
|---|---|
toArray(Set<T>) → [T] | Convert set to array. |
let s = Set(1, 2, 3);
s toArray println; -- [1, 2, 3]
length(set) / isEmpty(set)Returns the number of elements in the set, or whether there are none.
| Signature | Description |
|---|---|
length(Set<T>) → Int | Number of elements in the set. |
isEmpty(Set<T>) → Bool | True when the set has no elements. |
clear!(set)Mutating clear. Removes every element in place. Returns the same set for chaining.
| Signature | Description |
|---|---|
clear!(Set<T>) → Set<T> | Remove every element (mutates the set). Returns the same set. |
copy(set)Returns a shallow copy of the set. Use when an alias needs to be mutated independently. Nested Obj* elements are shared with the original.
| Signature | Description |
|---|---|
copy(Set<T>) → Set<T> | Shallow copy of a set. |
Functions that operate on the two immutable persistent collection types, written with a leading #. A persistent vector has type #[T] and is written #[1, 2, 3] — an immutable indexed sequence backed by a 32-way array-mapped trie. A persistent map has type #[K: V] and is written #["a": 1, "b": 2] (empty: #[:]) — an immutable keyed collection backed by a HAMT.
These are distinct types from the mutable Array / Map (just as List is distinct from Array); there is no implicit conversion between them. Because nothing is ever mutated, the update functions reuse the plain non-mutating names — there are no ! (bang) variants. Every “update” returns a new collection that shares structure with the original, which is left untouched.
An immutable indexed sequence. Indexing is cyclic like arrays: negative and out-of-range indices wrap. In addition to the functions below, persistent vectors support structural == / !=, concatenation with $, and use as a for-loop iterable (for (x : v) { … } yields elements).
length(pvec) / isEmpty(pvec)Returns the number of elements in the persistent vector, or whether there are none.
| Signature | Description |
|---|---|
length(#[T]) → Int | Number of elements. |
isEmpty(#[T]) → Bool | True when there are no elements. |
v[i]Returns the element at index i. Indexing is cyclic, like arrays — negative and out-of-range indices wrap around.
let v = #[1, 2, 3];
v[0] println; -- 1
v[-1] println; -- 3
v length println; -- 3
push(pvec, element)Returns a new persistent vector with element appended. The input is unchanged.
| Signature | Description |
|---|---|
push(#[T], T) → #[T] | Append an element (returns a new persistent vector). |
let v = #[1, 2, 3];
v push(4) println; -- #[1, 2, 3, 4]
v println; -- #[1, 2, 3] (unchanged)
put(pvec, index, element)Returns a new persistent vector with the element at index replaced. The input is unchanged.
| Signature | Description |
|---|---|
put(#[T], Int, T) → #[T] | Replace the element at an index (returns a new persistent vector). |
let v = #[1, 2, 3];
v put(1, 99) println; -- #[1, 99, 3]
v1 $ v2The $ operator concatenates two persistent vectors, returning a new persistent vector.
(#[1, 2] $ #[3, 4, 5]) println; -- #[1, 2, 3, 4, 5]
== / !=Persistent vectors compare by structure: equal if they have the same elements in the same order.
(#[1, 2, 3] == #[1, 2, 3]) println; -- true
map, filter, fold, scan, fold1, scan1, find, take, drop, takeWhile, dropWhile, stride, stutter, reverse, sort, sort(cmp), grade, zip, enumerate, cat, join, flatten — each returning a new persistent vector (or a scalar, for reductions). Auto-mapping also applies: a function expecting a scalar maps over a persistent vector, and @, @@, and cartesian @n all work.
let v = #[1, 2, 3];
v map(fn(x Int) { x * 10 }) println; -- #[10, 20, 30]
An immutable keyed collection. Any hashable key type works (String, Symbol, Int, …). Persistent maps support structural == / != (independent of insertion or hash order) and use as a for-loop iterable, which yields (key, value) tuples in hash order (not insertion order).
m[k]Returns Option<V> — safe for missing keys. Use unwrap / unwrapOr to extract the value.
let m = #["x": 1, "y": 2, "z": 3];
m["x"] unwrap println; -- 1
let im = #[1: "one", 2: "two"];
im[2] unwrap println; -- "two"
get(pmap, key) / get(pmap, key, default)Retrieves the value for a key. The two-argument form returns Option<V>; the three-argument form returns the value directly, using the provided default when the key is absent.
| Signature | Description |
|---|---|
get(#[K: V], K) → Option<V> | Get value for key; returns Option.some(v) or Option.none. |
get(#[K: V], K, V) → V | Get value for key; returns default if missing. |
let m = #["x": 1, "y": 2, "z": 3];
m get("z") unwrap println; -- 3
m get("w", 0) println; -- 0 (absent, returns default)
contains(pmap, key)Returns true if the key exists in the persistent map.
| Signature | Description |
|---|---|
contains(#[K: V], K) → Bool | Check if key exists. |
let m = #["x": 1, "y": 2];
m contains("x") println; -- true
length(pmap) / isEmpty(pmap)Returns the number of key-value pairs in the persistent map, or whether there are none.
| Signature | Description |
|---|---|
length(#[K: V]) → Int | Number of entries. |
isEmpty(#[K: V]) → Bool | True when there are no entries. |
put(pmap, key, value)Returns a new persistent map with the key-value pair inserted or updated. The input is unchanged.
| Signature | Description |
|---|---|
put(#[K: V], K, V) → #[K: V] | Insert-or-update a key-value pair (returns a new persistent map). |
let m = #["x": 1, "y": 2, "z": 3];
m put("w", 4) length println; -- 4
m length println; -- 3 (m unchanged)
remove(pmap, key)Returns a new persistent map without the given key. The input is unchanged.
| Signature | Description |
|---|---|
remove(#[K: V], K) → #[K: V] | Remove a key (returns a new persistent map). |
let m = #["x": 1, "y": 2];
m remove("x") contains("x") println; -- false
keys(pmap) / values(pmap)Return the keys (resp. values) of the persistent map as a persistent vector.
| Signature | Description |
|---|---|
keys(#[K: V]) → #[K] | All keys, as a persistent vector. |
values(#[K: V]) → #[V] | All values, as a persistent vector. |
merge(pmap1, pmap2)Returns a new persistent map containing all entries from both. On a key conflict, the right operand (pmap2) wins. Both inputs are unchanged.
| Signature | Description |
|---|---|
merge(#[K: V], #[K: V]) → #[K: V] | Merge two persistent maps (second wins on conflicts). |
(#["a": 1, "b": 2] merge(#["b": 20, "c": 30]))["b"] unwrap println; -- 20
== / !=Persistent maps compare by structure — equal if they contain the same key-value pairs, independent of insertion or hash order.
(#["a": 1, "b": 2] == #["b": 2, "a": 1]) println; -- true
Four functions convert between the mutable and persistent collection types. These are real O(n) builds, not cheap freeze/thaw views — the converted result is fully independent of any later mutation of the source.
| Signature | Description |
|---|---|
toPersistentVector([T]) → #[T] | Build a persistent vector from an array. |
toArray(#[T]) → [T] | Build a mutable array from a persistent vector. (toArray also accepts arrays, sets, etc.) |
toPersistentMap([K: V]) → #[K: V] | Build a persistent map from a mutable map. |
toMap(#[K: V]) → [K: V] | Build a mutable map from a persistent map. |
[5, 6, 7] toPersistentVector toArray println; -- [5, 6, 7]
["x": 1, "y": 2] toPersistentMap toMap length println; -- 2
-- The persistent copy is independent of later mutation:
var src = [1, 2, 3];
let f = src toPersistentVector;
src push!(4);
src length println; -- 4
f length println; -- 3 (f unaffected)
↑ Back to top
hash(x)Returns an integer hash value for any value. Consistent across calls: equal values always produce the same hash. User-defined hash overloads take priority over the built-in implementation.
| Signature | Description |
|---|---|
hash(Int) → Int | Hash an integer. |
hash(Float) → Int | Hash a float. |
hash(Bool) → Int | Hash a boolean. |
hash(Symbol) → Int | Hash a symbol. |
hash(T) → Int | Hash any object type (String, Array, Tuple, Struct, Enum, etc.). Uses structural hashing. |
hash(42) println; -- integer hash value
hash(3.14) println; -- integer hash value
hash('foo) println; -- integer hash value
-- Equal values produce equal hashes
println(hash((1, 2)) == hash((1, 2))); -- true
println(hash([1, 2, 3]) == hash([1, 2, 3])); -- true
== / !=)The == and != operators work on all types with matching operands. For object types (Structs, Tuples, Arrays, Enums, etc.), structural equality is used: two values are equal if all their fields/elements are equal. User-defined == overloads take priority over built-in structural equality.
-- Struct equality
struct Point { x Int, y Int }
let p1 = Point{1, 2};
println(p1 == Point{1, 2}); -- true
println(p1 == Point{3, 4}); -- false
-- Tuple equality
println((1, 2) == (1, 2)); -- true
-- Array equality
println([1, 2, 3] == [1, 2, 3]); -- true
-- Symbol equality
println('foo == 'foo); -- true
-- Enum equality
enum Color { red, green, blue }
println(Color.red == Color.red); -- true
-- User-defined == overrides structural equality
struct Vec2 { x Float, y Float }
fn ==(a Vec2, b Vec2) Bool {
let dx = a.x - b.x;
let dy = a.y - b.y;
dx * dx + dy * dy < 0.001 -- approximate equality
}
Both == and hash are cycle-safe: values that reference themselves (built through Ref assignment or in-place Array/Map/Set mutation) compare and hash without recursing forever. The common acyclic case pays essentially nothing — the ordinary recursive fast path runs first with a small work budget, and only a huge value or an actual cycle falls back to the cycle-aware algorithm.
Equality of cyclic values is bisimulation: two graphs are equal if their infinite unrollings are equal. Two separately built but identically shaped cycles compare equal, and shared substructure is detected so comparing large shared graphs stays fast. Isomorphic separately-built cycles also hash identically, so cyclic values work as Map keys and Set elements.
enum Tree { node [Tree], leaf Int }
var a = [Tree.leaf(1)];
a push!(Tree.node(a)); -- a[1] refers back to a: a cycle
var b = [Tree.leaf(1)];
b push!(Tree.node(b)); -- an independently built equal cycle
println(a == b); -- true (bisimulation)
println(hash(a) == hash(b)); -- true
var m = [Tree.node(a): "found"]; -- cyclic values as map keys work
m[Tree.node(b)] unwrap println; -- found
One edge case: bisimilar cycles of different unrolled length (a 1-node cycle versus its hand-built 2-node unrolling) compare equal but may hash differently. Such values are pathological as hash keys; everything structurally built stays consistent.
== and hash on Bytes compare and hash the byte contents (structural, like String).
Data values — including cyclic object graphs — can be serialized to a compact binary form (Bytes) and restored. "Data" means scalars and containers of them; types that carry behavior or live runtime state (functions, coroutines, futures, actors, Any, existentials) are not serializable — see the exact list under serialize below. Shared substructure is written once and cycles are stored as references, so serialization never duplicates or diverges. The bytes are deterministic: equal values produce identical bytes regardless of how they were built (Map/Set entries are written in a canonical order), which makes hash(serialize(x)) a stable content address.
serialize(x)| Signature | Description |
|---|---|
serialize(T) → Bytes | Encode a value of any serializable type into a self-describing binary buffer. |
Serializable: Bool, Int, Float, Symbol, String, Bytes, Complex, Fraction, ranges, arrays, lists, maps, sets, refs, tuples, structs, enums (including recursive ones), and persistent collections — any composition of these. Types containing functions, coroutines, futures, actors, Any, or existentials are rejected at compile time.
deserialize<T>(b)| Signature | Description |
|---|---|
deserialize<T>(Bytes) → T | Decode a buffer produced by serialize. The target type is given as an explicit type argument. |
The buffer embeds a structural signature of the type it was serialized as (field and case names, recursive layout). deserialize<T> validates it against T exactly; a mismatch — or any malformed/truncated input — raises a clean runtime error rather than decoding garbage. Compatibility is structural: an identical declaration in another program (same shape and the same spelled names) round-trips; renaming a field or case intentionally breaks it.
-- Round trip any data value
struct Point { x Float, y Float }
let p = Point { x: 1.5, y: 2.5 };
let b = serialize(p); -- Bytes
println(deserialize<Point>(b) == p); -- true
-- Cycles and sharing survive: aliases stay aliases
let shared = &10;
let out = deserialize<[Ref<Int>]>(serialize([shared, shared]));
out[0] <- 99;
*(out[1]) println; -- 99 (still one Ref)
-- Deterministic bytes: construction order does not matter
var m1 = ["a": 1]; m1["b"] = 2;
var m2 = ["b": 2]; m2["a"] = 1;
println(serialize(m1) == serialize(m2)); -- true
-- Wrong type or corrupt bytes: runtime error, never garbage
-- deserialize<Float>(serialize(42)); -- error: type signature mismatch
Bounded decoding. Declared sizes in a buffer are validated against its length, so a corrupt or hostile buffer cannot cause runaway allocation. Lazy lists are forced during serialization (bounded; an unbounded list raises a runtime error).
ordinal(enum_value)Returns the zero-based index of the enum case.
| Signature | Description |
|---|---|
ordinal(Enum) → Int | Get the case index of an enum value. |
enum Color { red, green, blue }
ordinal(Color.red) println; -- 0
ordinal(Color.green) println; -- 1
ordinal(Color.blue) println; -- 2
tag(enum_value)Returns the case name of an enum value as a Symbol.
| Signature | Description |
|---|---|
tag(Enum) → Symbol | Get the case name of an enum value. |
enum Color { red, green, blue }
tag(Color.red) println; -- 'red
tag(Color.green) println; -- 'green
tag(Color.blue) println; -- 'blue
enum Option { some Int, none }
tag(Option.some(42)) println; -- 'some
tag(Option.none) println; -- 'none
↑ Back to top
The following operators are compiled directly to VM instructions. They are not callable as named functions but are fundamental to the language. Arithmetic operators also work element-wise on Arrays and Tuples of numeric types.
| Operator | Types | Description |
|---|---|---|
+ | Int, Float, Fraction, Complex | Addition. |
- | Int, Float, Fraction, Complex | Subtraction. |
* | Int, Float, Fraction, Complex | Multiplication. |
/ | Int, Float, Fraction, Complex | Division. Int division produces a Fraction. |
% | Int | Modulo (remainder). |
- (unary) | Int, Float, Fraction, Complex | Negation. |
// | Int | Truncating integer division. |
| Operator | Types | Description |
|---|---|---|
== | All types (matching operands) | Equal. Structural equality for object types. User-defined overloads take priority. |
!= | All types (matching operands) | Not equal. Structural inequality for object types. User-defined overloads take priority. |
< | Int, Float, Fraction, String | Less than. |
<= | Int, Float, Fraction, String | Less than or equal. |
> | Int, Float, Fraction, String | Greater than. |
>= | Int, Float, Fraction, String | Greater than or equal. |
| Operator | Types | Description |
|---|---|---|
& | Int | Bitwise AND. |
| | Int | Bitwise OR. |
^ | Int | Bitwise XOR. |
~ | Int | Bitwise NOT (complement). |
<< | Int | Left shift. |
>> | Int | Right shift (arithmetic, sign-extending). |
>>> | Int | Unsigned right shift (zero-filling). |
| Operator | Types | Description |
|---|---|---|
! | Bool | Logical NOT. |
&& | Bool | Logical AND (short-circuit). |
|| | Bool | Logical OR (short-circuit). |
| Operator | Types | Description |
|---|---|---|
$ | String, Array, List, Tuple | Concatenation. |
Implicit conversions follow the numeric tower: Int → Fraction → Float → Complex. Implicit conversions are inserted automatically when a value of a lower-ranked type is used where a higher-ranked type is expected.
Explicit conversion functions are provided for all numeric types, including conversions down the tower (e.g. Float to Int):
toInt(x)Convert a numeric value to Int by truncating toward zero.
| Signature | Description |
|---|---|
toInt(Int) → Int | Identity — returns the value unchanged. |
toInt(Float) → Int | Truncate toward zero (fractional part discarded). |
toInt(Fraction) → Int | Truncate toward zero (numerator/denominator as float, then truncated). |
toInt(3.7) println; -- 3
toInt(-2.9) println; -- -2
toInt(7/2) println; -- 3
toFloat(x)Convert a numeric value to Float.
| Signature | Description |
|---|---|
toFloat(Int) → Float | Integer to double-precision float. |
toFloat(Float) → Float | Identity — returns the value unchanged. |
toFloat(Fraction) → Float | Fraction to double-precision float (numerator/denominator). |
toFloat(Complex) → Float | Returns the real part, discarding the imaginary part. |
toFloat(5) println; -- 5.0
toFloat(7/2) println; -- 3.5
toFloat(3.0 + 4.0i) println; -- 3.0
toFraction(x)Convert a numeric value to Fraction.
| Signature | Description |
|---|---|
toFraction(Int) → Fraction | Integer to fraction (denominator 1). |
toFraction(Fraction) → Fraction | Identity — returns the value unchanged. |
toFraction(5) println; -- 5/1
toComplex(x)Convert a numeric value to Complex (imaginary part 0).
| Signature | Description |
|---|---|
toComplex(Int) → Complex | Integer to complex (imaginary part 0). |
toComplex(Float) → Complex | Float to complex (imaginary part 0). |
toComplex(Fraction) → Complex | Fraction to complex (via float, imaginary part 0). |
toComplex(Complex) → Complex | Identity — returns the value unchanged. |
toComplex(5) println; -- 5+0i
toComplex(3.14) println; -- 3.14+0i
toComplex(7/2) println; -- 3.5+0i
↑ Back to top
| Function | Description |
|---|---|
print(...) | Print values without a trailing newline. Accepts any number of arguments of any type. Does not flush output. |
println(...) | Print values followed by a newline. Accepts any number of arguments of any type. Flushes output. |
Both print and println accept any number of arguments of any type. Multiple arguments are separated by spaces. They participate in auto-mapping: passing an array with @ prints each element individually.
-- println prints values followed by a newline
println(42); -- 42
println("hello", "world"); -- hello world
println(1, 2.5, true); -- 1 2.5 true
println(); -- (empty line)
-- print does not add a newline
print("x=");
println(42); -- x=42
-- Pipeline syntax
42 println; -- 42
"hello" println; -- hello
-- Auto-mapping: print each element on its own line
[1, 2, 3] @ println; -- 1 2 3 (each on its own line)
panic(message)Print Error: <message> and halt execution — the same trap unwrap springs on a none, with a message of your choosing. Statements after the panic do not run; a script that panics exits with a nonzero status. Use it in library code that must not continue past a failure — for example, defSynth/defSynthX panic when a synthdef fails to compile.
| Signature | Description |
|---|---|
panic(String) → Void | Print the message and halt execution. |
"before" println; -- before
panic("something went wrong"); -- Error: something went wrong
"after" println; -- never runs
toString(x)Convert any value to its printed representation. The result is exactly the text that print would output for the value, as a single-line String with no width awareness (see prettyString below for the width-aware form). Works on values of every type: numbers, Bool, Symbol, String, containers, tuples, structs, enums, and so on.
| Signature | Description |
|---|---|
toString(T) → String | The printed form of the value. For a String argument this is the identity. |
Note that strings are rendered without quotes, both at top level and inside containers, and symbols are rendered without the leading '.
toString(42) println; -- 42
toString(7/2) println; -- 7/2
toString(3.0 + 4.0i) println; -- 3+4i
toString([1, 2, 3]) println; -- [1, 2, 3]
toString(["a", "b"]) println; -- [a, b] (strings unquoted)
toString((1, "two", 3.0)) println; -- (1, two, 3.0)
struct Point { x Float; y Float; }
toString(Point { x: 1.5, y: 2.5 }) println;
-- Point { x: 1.5, y: 2.5 }
-- Useful for building strings with the $ concatenation operator
let s = "answer: " $ toString(42);
s println; -- answer: 42
-- Pipeline syntax
[1, 2, 3] toString println; -- [1, 2, 3]
prettyString(x) / prettyPrint(x)Width-aware pretty printing. Each container prints on one line when it fits the target width, and otherwise breaks one element per line with two-space indentation. At a very large width the output is identical to toString. The REPL and notebook cells display results this way automatically.
| Signature | Description |
|---|---|
prettyString(T) → String | Render at the default width (80 columns). |
prettyString(T, Int) → String | Render at the given line width. |
prettyPrint(T) → VoidprettyPrint(T, Int) → Void | Print the pretty form followed by a newline. |
let v = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
v prettyPrint; -- fits in 80 columns: one line
-- [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
v prettyPrint(20); -- narrower: one element per line
-- [
-- [1, 2, 3],
-- [4, 5, 6],
-- [7, 8, 9]
-- ]
struct Point { x Float, y Float }
Point { x: 1.5, y: 2.5 } prettyPrint(12);
-- Point {
-- x: 1.5,
-- y: 2.5
-- }
Cyclic values print safely — in both print/toString and the pretty printer. A container that re-enters itself prints ^n^, meaning “this is the same object n container levels up,” and recursion stops there:
enum Tree { node [Tree], leaf Int }
var a = [Tree.leaf(1)];
a push!(Tree.node(a));
a println; -- [Tree.leaf(1), Tree.node(^1^)]
Control how many elements are displayed when printing lists.
| Function | Signature | Description |
|---|---|---|
getListPrintLimit() | () → Int | Get the current maximum number of list elements to display when printing. |
setListPrintLimit(n) | Int → Int | Set the maximum number of list elements to display. Returns the previous limit. |
let old = setListPrintLimit(3);
(1..10) toList println; -- List(1, 2, 3, ...)
setListPrintLimit(old); -- restore previous limit
getListPrintLimit(); -- check current limit
Per-VM safety limits on the cycle-safe == / hash /
print / serialize traversals. Each limit guards against a runaway
traversal (a C++ stack overflow, or forcing an unbounded lazy list
forever); a valid program that legitimately exceeds one can raise it
at runtime. Setters return the previous value and clamp to
>= 1. Initial values come from the host's VM
configuration (in the app: Language Settings).
| Function | Signature | Description |
|---|---|---|
getGraphMaxDepth() | () → Int | Current nesting-depth limit for ==, hash, and serialize traversals (default 10000). Exceeding it raises a runtime error. |
setGraphMaxDepth(n) | Int → Int | Set the traversal depth limit. Returns the previous limit. |
getLazyForceLimit() | () → Int | Current cap on lazy list-node forces per ==/hash/serialize traversal (default 10000), so an unbounded lazy list raises instead of hanging. |
setLazyForceLimit(n) | Int → Int | Set the lazy force cap. Returns the previous limit. |
getPrintMaxDepth() | () → Int | Current container-nesting depth at which printing elides with ... (default 200). |
setPrintMaxDepth(n) | Int → Int | Set the print-depth limit. Returns the previous limit. |
let old = setGraphMaxDepth(50000);
deepA == deepB; -- a 20000-deep compare now succeeds
setGraphMaxDepth(old); -- restore previous limit
↑ Back to top
Whole-file reads and writes, directory operations, and environment access. Every function in this section performs blocking syscalls and is not real-time safe: calling one in a program compiled for a real-time VM (--rt, silo code) is a compile-time type error. Fallible operations return Option (none on any OS error); mutating operations return a success Bool.
There are no streaming file handles — files are read and written whole. For structured binary data, use readFileBytes with the Bytes accessors (u8At, f64At, utf8At, …). Ergonomic wrappers (readLines, readFileOr, Result-returning variants) live in the std.fs module; pure path-string helpers live in std.path (see the Standard Library reference).
| Signature | Description |
|---|---|
readFile(String) → Option[String] | The file's entire contents as a string. |
readFileBytes(String) → Option[Bytes] | The file's entire contents as bytes. |
writeFile(String, String) → BoolwriteFile(String, Bytes) → Bool | Replace the file's contents; true on success. |
appendFile(String, String) → BoolappendFile(String, Bytes) → Bool | Append to the file (creating it if missing). |
writeFile("/tmp/notes.txt", "hello\n");
appendFile("/tmp/notes.txt", "world\n");
readFile("/tmp/notes.txt") unwrapOr("") print; -- hello\nworld\n
readFile("/missing") isNone; -- true
Each read/write builtin has an Async variant returning a Future. The builtin returns immediately; the syscall runs on the host's I/O worker thread and the Future resolves when it lands, so a long read no longer stalls the VM (actor service, OSC/NATS handlers, UI callbacks keep running). await the Future for the same value the synchronous form returns. Completion order is unobservable — awaited values arrive in program order — and in a host with no I/O worker (an embedded bare VM) the variants degrade to synchronous execution with identical semantics. They are still NRT: a Pending Future is cheap, but resolving one with file contents on the audio thread is not, so real-time VMs reject them at compile time like the rest of this section.
| Signature | Description |
|---|---|
readFileAsync(String) → Future[Option[String]] | Off-thread readFile. |
readFileBytesAsync(String) → Future[Option[Bytes]] | Off-thread readFileBytes. |
writeFileAsync(String, String) → Future[Bool]writeFileAsync(String, Bytes) → Future[Bool] | Off-thread writeFile. |
appendFileAsync(String, String) → Future[Bool]appendFileAsync(String, Bytes) → Future[Bool] | Off-thread appendFile. |
-- Start both reads, then await: the files load concurrently.
let a = readFileAsync("/tmp/one.txt");
let b = readFileAsync("/tmp/two.txt");
(await a) unwrapOr("") println;
(await b) unwrapOr("") println;
| Signature | Description |
|---|---|
fileExists(String) → Bool | True for any existing entry (file or directory). |
isDirectory(String) → Bool | True if the path is a directory. |
fileSize(String) → Option[Int] | Size in bytes of a regular file. |
fileModTime(String) → Option[Float] | Last-modified time, Unix seconds. |
listDir(String) → Option[[String]] | Entry names, sorted; no "."/"..". |
makeDir(String) → Bool | Create the directory and missing parents; true if it exists afterwards. |
removeFile(String) → Bool | Delete a file (not a directory). |
renameFile(String, String) → Bool | Rename/move a file. |
makeDir("/tmp/proj/samples");
listDir("/tmp/proj") unwrap println; -- [samples]
fileSize("/tmp/kick.wav") unwrapOr(-1);
| Signature | Description |
|---|---|
getEnv(String) → Option[String] | An environment variable's value. |
programArgs() → [String] | CLI arguments after the script filename (tzpl run.x a b → [a, b]). |
currentDir() → Option[String] | The process's current working directory. |
getEnv("HOME") unwrapOr("/") println;
programArgs() println;
↑ Back to top
Real FFT over [Float] in double precision. The input length must be a power of two ≥ 4; anything else returns none. Spectra use a packed split-complex layout of the same length N as the signal: [re[0], re[1], …, re[N/2-1], im[0], im[1], …, im[N/2-1]], where re[0] is the DC component and im[0] carries the (purely real) Nyquist component. fft produces the standard unnormalized DFT (a full-scale cosine at bin k yields re[k] = N/2); ifft is its exact inverse: ifft(fft(x)) unwrap == x to double precision.
Not real-time safe (FFT setups are cached with the system allocator): calling either in a program compiled for a real-time VM is a compile-time type error. Typical uses — wavetable generation (see wavetables.x and the oscillators chapter of Writing SynthDefs), offline analysis — run at patch-build time.
| Signature | Description |
|---|---|
fft([Float]) → Option[[Float]] | Forward real FFT: N time samples → packed split spectrum. none unless N is a power of two ≥ 4. |
ifft([Float]) → Option[[Float]] | Inverse real FFT: packed split spectrum → N time samples. Exact inverse of fft. |
-- Build one period of a unit-amplitude sine directly in the spectrum:
-- partial k at amplitude a is im[k] = -a*N/2 (sine) / re[k] = a*N/2 (cosine).
let n = 512;
var spec = [Float]();
for (i : (1 .. n)) { spec push!(0.0); }
spec[n // 2 + 1] = -(n toFloat) / 2.0; -- im[1]: sin(2*pi*x)
let table = ifft(spec) unwrap;
fft([1.0, 2.0, 3.0]) isNone; -- true: not a power of two
disassemble(fn)Print the generated bytecode for a function. Accepts any function value — named functions, lambdas, and closures. For built-in (primitive) functions, which have no bytecode, a message is printed instead.
| Signature | Description |
|---|---|
fn(...) T → Void | Print the instruction stream for the given function. |
The output includes a header with the function name, register count, argument count, and type signature, followed by each instruction with its offset, opcode name, register operands, and any constants, jump targets, or type annotations.
-- Disassemble a named function
fn add(a Int, b Int) Int = a + b;
disassemble(add);
-- Output:
-- -- add (3 regs, 2 args)
-- 0 ADD_INT r2, r0, r1
-- 2 RETURN r2
-- Disassemble a lambda
let double = fn(x Int) Int = x * 2;
disassemble(double);
-- Output:
-- -- <lambda> (3 regs, 1 args, type fn(Int) Int)
-- 0 LOAD_INT r1 ; 2
-- 3 MUL_INT r2, r0, r1
-- 5 RETURN r2
-- Disassemble a recursive function
fn fib(n Int) Int {
if (n <= 1) { return n; }
else { return fib(n - 1) + fib(n - 2); }
}
disassemble(fib);
-- Shows CALL instructions with resolved function names like (fib)
typeName<T>()Returns the display name of a type, given as an explicit type argument. (Built-in functions can take explicit type arguments with the f<T>(…) call form — the same syntax deserialize<T> uses.)
| Signature | Description |
|---|---|
typeName<T>() → String | The display name of T. |
typeName<Int>() println; -- Int
typeName<[Int]>() println; -- [Int]
typeName<[String: Float]>() println; -- [String:Float]
typeName<(Int, Bool)>() println; -- (Int, Bool)
typeRepr(x)A low-level debugging aid that prints how a value's type is represented internally: its representation class (Atom, Inline, Pointer, …), its size in 64-bit words, whether it is a value type, whether it is recursive, and — for composites — the field layout with word offsets. The argument is a normal value; its static type is what gets described. Intended for understanding memory layout and inline-promotion decisions, not for use in programs.
| Signature | Description |
|---|---|
typeRepr(T) → Void | Print the internal representation of T to standard output. |
typeRepr(42);
-- Int: repr=Atom sizeWords=1 value=1 recursive=0
typeRepr(7/2);
-- Fraction: repr=Inline sizeWords=2 value=1 recursive=0
struct Point { x Float; y Float; }
typeRepr(Point { x: 1.5, y: 2.5 });
-- Point: repr=Inline sizeWords=2 value=1 recursive=0 inline=2 layout=[(@0,1w,Float),(@1,1w,Float)]
typeRepr([1, 2, 3]);
-- [Int]: repr=Pointer sizeWords=1 value=1 recursive=0
Note: disassemble and typeRepr are not real-time safe — they write to standard output. For disassemble, if a function has multiple overloads you must disambiguate by binding it to a variable with a specific type first, since overloaded names cannot be used as values directly.
Quick reference of which named functions are available for each type.
abs, sign, min, max, clamp, cmp,
gcd, lcm,
clz, clo, ctz, cto, popCount,
rotl, rotr, bitCeil, bitFloor, bitWidth, hasSingleBit,
hash
abs, sign, min, max, clamp, cmp,
floor, ceil, round, trunc, frac,
sqrt, cbrt, pow, hypot,
exp, exp2, exp10, expm1,
log, log2, log10, log1p,
sin, cos, tan,
asin, acos, atan, atan2,
sinpi, cospi, tanpi,
sinh, cosh, tanh,
asinh, acosh, atanh,
erf, erfc, tgamma, lgamma,
copysign, nextafter,
isNan, isInf, isFinite, isNormal,
hash
abs, sign, min, max, clamp, cmp,
numer, denom,
hash
abs, sqrt, pow,
real, imag, arg, norm, conj, polar,
exp, log,
sin, cos, tan,
asin, acos, atan,
sinh, cosh, tanh,
asinh, acosh, atanh,
hash
length, substring, contains,
startsWith, endsWith, split,
trim, toUpper, toLower, replace,
codePoints,
fmt,
s[i] (byte indexing),
toSymbol,
min, max, cmp,
hash
hash
length, toArray, toList
length,
map, filter, fold, scan, fold1, scan1, find,
zip, enumerate,
take, drop, takeWhile, dropWhile,
stride, stutter,
cat, join, flatten,
reverse, push, pop, sort, muss,
hash
length,
head, tail, cons, isNil, notNil,
map, filter, fold, scan, fold1, scan1, find,
zip, enumerate,
take, drop, takeWhile, dropWhile,
stride, stutter,
cat, join, flatten,
cyc, ncyc, hang, iter,
hash
next, toList
length,
get, put, remove, contains,
keys, values, merge,
hash
length,
add, remove, contains,
union, intersection, difference,
toArray,
hash
ordinal,
tag,
hash
ref, deref, setref
any, toAnyArray, as(Type)
disassemble
==, != (structural equality),
hash