Silt Standard Library Reference

Complete API reference for every built-in function in silt.

Module Index

ModuleFunctionsDescription
Globals12print, println, panic, variant constructors, type descriptors
list31Create, transform, query, and iterate over ordered collections
string27Split, join, search, transform, and classify strings
map14Lookup, insert, merge, and iterate over key-value maps
set15Create, combine, query, and iterate over unordered unique collections
int6Parse, convert, and compare integers
float9Parse, round, convert, and compare floats
result7Transform and query Result(a, e) values
option6Transform and query Option(a) values
io5File I/O, stdin, command-line args, debug inspection
fs1Filesystem path queries
test3Assertions for test scripts
regex9Match, find, split, replace, and capture with regular expressions
json5Parse JSON into typed records/maps, serialize values to JSON
math11 + 2Trigonometry, logarithms, exponentiation, and constants
channel8Bounded channels for cooperative concurrency
task3Spawn, join, and cancel cooperative tasks

Total: 162 names (12 globals + 4 type descriptors + 146 module functions/constants)

Globals

Always available. No import or qualification needed.

Summary

NameSignatureDescription
print(a) -> ()Print a value without trailing newline
println(a) -> ()Print a value with trailing newline
panic(String) -> aCrash with an error message
Ok(a) -> Result(a, e)Construct a success Result
Err(e) -> Result(a, e)Construct an error Result
Some(a) -> Option(a)Construct a present Option
NoneOption(a)The absent Option value (not a function)
Stop(a) -> Step(a)Signal early termination in list.fold_until
Continue(a) -> Step(a)Signal continuation in list.fold_until
Message(a) -> ChannelResult(a)Wraps a received channel value
ClosedChannelResult(a)Channel is closed
EmptyChannelResult(a)Channel buffer empty (non-blocking receive)

Additionally, four type descriptors are in the global namespace for use with json.parse_map and similar type-directed APIs:

NameDescription
IntInteger type descriptor
FloatFloat type descriptor
StringString type descriptor
BoolBoolean type descriptor

print

print(value: a) -> ()

Prints a value to stdout. Does not append a newline. Multiple values in a single call are separated by spaces.

fn main() {
    print("hello ")
    print("world")
    // output: hello world
}

println

println(value: a) -> ()

Prints a value to stdout followed by a newline.

fn main() {
    println("hello, world")
    // output: hello, world\n
}

panic

panic(message: String) -> a

Terminates execution with an error message. The return type is polymorphic because panic never returns — it can appear anywhere a value is expected.

fn main() {
    panic("something went wrong")
}

Ok

Ok(value: a) -> Result(a, e)

Constructs a success variant of Result.

fn main() {
    let r = Ok(42)
    // r is Result(Int, e)
}

Err

Err(error: e) -> Result(a, e)

Constructs an error variant of Result.

fn main() {
    let r = Err("not found")
    // r is Result(a, String)
}

Some

Some(value: a) -> Option(a)

Constructs a present variant of Option.

fn main() {
    let x = Some(42)
    match x {
        Some(n) -> println(n)
        None -> println("nothing")
    }
}

None

None : Option(a)

The absent variant of Option. This is a value, not a function.

fn main() {
    let x = None
    println(option.is_none(x))  // true
}

Stop

Stop(value: a) -> Step(a)

Signals early termination from list.fold_until. The value becomes the final accumulator result.

fn main() {
    let result = list.fold_until([1, 2, 3, 4, 5], 0) { acc, x ->
        when acc + x > 6 -> Stop(acc)
        else -> Continue(acc + x)
    }
    println(result)  // 6
}

Continue

Continue(value: a) -> Step(a)

Signals continuation in list.fold_until. The value becomes the next accumulator.

Message

Message(value: a) -> ChannelResult(a)

Wraps a value received from a channel. Returned by channel.receive and channel.try_receive when a value is available.

fn main() {
    let ch = channel.new(1)
    channel.send(ch, 42)
    let Message(v) = channel.receive(ch)
    println(v)  // 42
}

Closed

Closed : ChannelResult(a)

Indicates the channel has been closed. Returned by channel.receive and channel.try_receive when no more messages will arrive.

Empty

Empty : ChannelResult(a)

Indicates the channel buffer is currently empty but not closed. Only returned by channel.try_receive (the non-blocking variant).

list

Functions for working with ordered, immutable lists (List(a)). Lists use [...] literal syntax and support the range operator 1..5.

Summary

FunctionSignatureDescription
all(List(a), (a) -> Bool) -> BoolTrue if predicate holds for every element
any(List(a), (a) -> Bool) -> BoolTrue if predicate holds for at least one element
append(List(a), a) -> List(a)Add an element to the end
concat(List(a), List(a)) -> List(a)Concatenate two lists
contains(List(a), a) -> BoolCheck if element is in list
drop(List(a), Int) -> List(a)Remove first n elements
each(List(a), (a) -> ()) -> ()Call function for each element (side effects)
enumerate(List(a)) -> List((Int, a))Pair each element with its index
filter(List(a), (a) -> Bool) -> List(a)Keep elements matching predicate
filter_map(List(a), (a) -> Option(b)) -> List(b)Filter and transform in one pass
find(List(a), (a) -> Bool) -> Option(a)First element matching predicate
flat_map(List(a), (a) -> List(b)) -> List(b)Map then flatten
flatten(List(List(a))) -> List(a)Flatten one level of nesting
fold(List(a), b, (b, a) -> b) -> bReduce to a single value
fold_until(List(a), b, (b, a) -> Step(b)) -> bFold with early termination
get(List(a), Int) -> Option(a)Element at index, or None
group_by(List(a), (a) -> k) -> Map(k, List(a))Group elements by key function
head(List(a)) -> Option(a)First element, or None
last(List(a)) -> Option(a)Last element, or None
length(List(a)) -> IntNumber of elements
map(List(a), (a) -> b) -> List(b)Transform each element
prepend(List(a), a) -> List(a)Add an element to the front
reverse(List(a)) -> List(a)Reverse element order
set(List(a), Int, a) -> List(a)Return new list with element at index replaced
sort(List(a)) -> List(a)Sort in natural order
sort_by(List(a), (a) -> b) -> List(a)Sort by key function
tail(List(a)) -> List(a)All elements except the first
take(List(a), Int) -> List(a)Keep first n elements
unfold(a, (a) -> Option((b, a))) -> List(b)Build a list from a seed
unique(List(a)) -> List(a)Remove duplicates, preserving first occurrence
zip(List(a), List(b)) -> List((a, b))Pair elements from two lists

list.all

list.all(xs: List(a), f: (a) -> Bool) -> Bool

Returns true if f returns true for every element. Short-circuits on the first false.

fn main() {
    let result = list.all([2, 4, 6]) { x -> x % 2 == 0 }
    println(result)  // true
}

list.any

list.any(xs: List(a), f: (a) -> Bool) -> Bool

Returns true if f returns true for at least one element. Short-circuits on the first true.

fn main() {
    let result = list.any([1, 3, 4]) { x -> x % 2 == 0 }
    println(result)  // true
}

list.append

list.append(xs: List(a), elem: a) -> List(a)

Returns a new list with elem added at the end.

fn main() {
    let xs = [1, 2, 3] |> list.append(4)
    println(xs)  // [1, 2, 3, 4]
}

list.concat

list.concat(xs: List(a), ys: List(a)) -> List(a)

Concatenates two lists into a single list.

fn main() {
    let result = list.concat([1, 2], [3, 4])
    println(result)  // [1, 2, 3, 4]
}

list.contains

list.contains(xs: List(a), elem: a) -> Bool

Returns true if elem is in the list (by value equality).

fn main() {
    println(list.contains([1, 2, 3], 2))  // true
    println(list.contains([1, 2, 3], 5))  // false
}

list.drop

list.drop(xs: List(a), n: Int) -> List(a)

Returns the list without its first n elements. If n >= length, returns an empty list.

fn main() {
    let result = list.drop([1, 2, 3, 4, 5], 2)
    println(result)  // [3, 4, 5]
}

list.each

list.each(xs: List(a), f: (a) -> ()) -> ()

Calls f for every element in the list. Used for side effects. Returns unit.

fn main() {
    [1, 2, 3] |> list.each { x -> println(x) }
}

list.enumerate

list.enumerate(xs: List(a)) -> List((Int, a))

Returns a list of (index, element) tuples, with indices starting at 0.

fn main() {
    let pairs = list.enumerate(["a", "b", "c"])
    // [(0, "a"), (1, "b"), (2, "c")]
    list.each(pairs) { (i, v) -> println("{i}: {v}") }
}

list.filter

list.filter(xs: List(a), f: (a) -> Bool) -> List(a)

Returns a list containing only the elements for which f returns true.

fn main() {
    let evens = [1, 2, 3, 4, 5] |> list.filter { x -> x % 2 == 0 }
    println(evens)  // [2, 4]
}

list.filter_map

list.filter_map(xs: List(a), f: (a) -> Option(b)) -> List(b)

Applies f to each element. Keeps the inner values from Some results and discards None results. Combines filtering and mapping in one pass.

fn main() {
    let results = ["1", "abc", "3"] |> list.filter_map { s ->
        match int.parse(s) {
            Ok(n) -> Some(n * 10)
            Err(_) -> None
        }
    }
    println(results)  // [10, 30]
}

list.find

list.find(xs: List(a), f: (a) -> Bool) -> Option(a)

Returns Some(element) for the first element where f returns true, or None if no match is found.

fn main() {
    let result = list.find([1, 2, 3, 4]) { x -> x > 2 }
    println(result)  // Some(3)
}

list.flat_map

list.flat_map(xs: List(a), f: (a) -> List(b)) -> List(b)

Maps each element to a list, then flattens the results into a single list.

fn main() {
    let result = [1, 2, 3] |> list.flat_map { x -> [x, x * 10] }
    println(result)  // [1, 10, 2, 20, 3, 30]
}

list.flatten

list.flatten(xs: List(List(a))) -> List(a)

Flattens one level of nesting. Non-list elements are kept as-is.

fn main() {
    let result = list.flatten([[1, 2], [3], [4, 5]])
    println(result)  // [1, 2, 3, 4, 5]
}

list.fold

list.fold(xs: List(a), init: b, f: (b, a) -> b) -> b

Reduces a list to a single value. Starts with init, then calls f(acc, elem) for each element.

fn main() {
    let sum = [1, 2, 3] |> list.fold(0) { acc, x -> acc + x }
    println(sum)  // 6
}

list.fold_until

list.fold_until(xs: List(a), init: b, f: (b, a) -> Step(b)) -> b

Like fold, but the callback returns Continue(acc) to keep going or Stop(value) to terminate early.

fn main() {
    // Sum until we exceed 5
    let result = list.fold_until([1, 2, 3, 4, 5], 0) { acc, x ->
        let next = acc + x
        when next > 5 -> Stop(acc)
        else -> Continue(next)
    }
    println(result)  // 3
}

list.get

list.get(xs: List(a), index: Int) -> Option(a)

Returns Some(element) at the given index, or None if out of bounds.

fn main() {
    let xs = [10, 20, 30]
    println(list.get(xs, 1))   // Some(20)
    println(list.get(xs, 10))  // None
}

list.group_by

list.group_by(xs: List(a), f: (a) -> k) -> Map(k, List(a))

Groups elements by the result of applying f. Returns a map from keys to lists of elements that produced that key.

fn main() {
    let groups = [1, 2, 3, 4, 5, 6] |> list.group_by { x -> x % 2 }
    // #{0: [2, 4, 6], 1: [1, 3, 5]}
}

list.head

list.head(xs: List(a)) -> Option(a)

Returns Some(first_element) or None if the list is empty.

fn main() {
    println(list.head([1, 2, 3]))  // Some(1)
    println(list.head([]))         // None
}

list.last

list.last(xs: List(a)) -> Option(a)

Returns Some(last_element) or None if the list is empty.

fn main() {
    println(list.last([1, 2, 3]))  // Some(3)
    println(list.last([]))         // None
}

list.length

list.length(xs: List(a)) -> Int

Returns the number of elements in the list.

fn main() {
    println(list.length([1, 2, 3]))  // 3
    println(list.length([]))         // 0
}

list.map

list.map(xs: List(a), f: (a) -> b) -> List(b)

Returns a new list with f applied to each element.

fn main() {
    let doubled = [1, 2, 3] |> list.map { x -> x * 2 }
    println(doubled)  // [2, 4, 6]
}

list.prepend

list.prepend(xs: List(a), elem: a) -> List(a)

Returns a new list with elem added at the front.

fn main() {
    let xs = [2, 3] |> list.prepend(1)
    println(xs)  // [1, 2, 3]
}

list.reverse

list.reverse(xs: List(a)) -> List(a)

Returns a new list with elements in reverse order.

fn main() {
    println(list.reverse([1, 2, 3]))  // [3, 2, 1]
}

list.set

list.set(xs: List(a), index: Int, value: a) -> List(a)

Returns a new list with the element at index replaced by value. Panics if the index is out of bounds.

fn main() {
    let xs = list.set([10, 20, 30], 1, 99)
    println(xs)  // [10, 99, 30]
}

list.sort

list.sort(xs: List(a)) -> List(a)

Returns a new list sorted in natural (ascending) order.

fn main() {
    println(list.sort([3, 1, 2]))  // [1, 2, 3]
}

list.sort_by

list.sort_by(xs: List(a), key: (a) -> b) -> List(a)

Returns a new list sorted by the result of applying the key function to each element.

fn main() {
    let words = ["banana", "fig", "apple"]
    let sorted = words |> list.sort_by { w -> string.length(w) }
    println(sorted)  // ["fig", "apple", "banana"]
}

list.tail

list.tail(xs: List(a)) -> List(a)

Returns all elements except the first. Returns an empty list if the input is empty.

fn main() {
    println(list.tail([1, 2, 3]))  // [2, 3]
    println(list.tail([]))         // []
}

list.take

list.take(xs: List(a), n: Int) -> List(a)

Returns the first n elements. If n >= length, returns the whole list.

fn main() {
    println(list.take([1, 2, 3, 4, 5], 3))  // [1, 2, 3]
}

list.unfold

list.unfold(seed: a, f: (a) -> Option((b, a))) -> List(b)

Builds a list from a seed value. The function returns Some((element, next_seed)) to emit an element and continue, or None to stop.

fn main() {
    let countdown = list.unfold(5) { n ->
        when n <= 0 -> None
        else -> Some((n, n - 1))
    }
    println(countdown)  // [5, 4, 3, 2, 1]
}

list.unique

list.unique(xs: List(a)) -> List(a)

Removes duplicate elements, preserving the order of first occurrences.

fn main() {
    println(list.unique([1, 2, 1, 3, 2]))  // [1, 2, 3]
}

list.zip

list.zip(xs: List(a), ys: List(b)) -> List((a, b))

Pairs up elements from two lists. Stops at the shorter list.

fn main() {
    let pairs = list.zip([1, 2, 3], ["a", "b", "c"])
    println(pairs)  // [(1, "a"), (2, "b"), (3, "c")]
}

string

Functions for working with immutable strings. Strings use "..." literal syntax with {expr} interpolation.

Summary

FunctionSignatureDescription
char_code(String) -> IntUnicode code point of first character
chars(String) -> List(String)Split string into single-character strings
contains(String, String) -> BoolCheck if substring exists
ends_with(String, String) -> BoolCheck suffix
from_char_code(Int) -> StringCharacter from Unicode code point
index_of(String, String) -> Option(Int)Byte position of first occurrence
is_alnum(String) -> BoolFirst char is alphanumeric
is_alpha(String) -> BoolFirst char is alphabetic
is_digit(String) -> BoolFirst char is ASCII digit
is_empty(String) -> BoolString has zero length
is_lower(String) -> BoolFirst char is lowercase
is_upper(String) -> BoolFirst char is uppercase
is_whitespace(String) -> BoolFirst char is whitespace
join(List(String), String) -> StringJoin list with separator
length(String) -> IntByte length
pad_left(String, Int, String) -> StringPad to width on the left
pad_right(String, Int, String) -> StringPad to width on the right
repeat(String, Int) -> StringRepeat string n times
replace(String, String, String) -> StringReplace all occurrences
slice(String, Int, Int) -> StringSubstring by character indices
split(String, String) -> List(String)Split on separator
starts_with(String, String) -> BoolCheck prefix
to_lower(String) -> StringConvert to lowercase
to_upper(String) -> StringConvert to uppercase
trim(String) -> StringRemove leading and trailing whitespace
trim_end(String) -> StringRemove trailing whitespace
trim_start(String) -> StringRemove leading whitespace

string.char_code

string.char_code(s: String) -> Int

Returns the Unicode code point of the first character. Panics on empty strings.

fn main() {
    println(string.char_code("A"))  // 65
}

string.chars

string.chars(s: String) -> List(String)

Splits the string into a list of single-character strings.

fn main() {
    println(string.chars("hi"))  // ["h", "i"]
}

string.contains

string.contains(s: String, sub: String) -> Bool

Returns true if sub appears anywhere in s.

fn main() {
    println(string.contains("hello world", "world"))  // true
}

string.ends_with

string.ends_with(s: String, suffix: String) -> Bool

Returns true if s ends with suffix.

fn main() {
    println(string.ends_with("hello.silt", ".silt"))  // true
}

string.from_char_code

string.from_char_code(code: Int) -> String

Converts a Unicode code point to a single-character string. Panics on invalid code points.

fn main() {
    println(string.from_char_code(65))  // "A"
}

string.index_of

string.index_of(s: String, needle: String) -> Option(Int)

Returns Some(byte_index) of the first occurrence of needle in s, or None if not found.

fn main() {
    println(string.index_of("hello", "ll"))  // Some(2)
    println(string.index_of("hello", "z"))   // None
}

string.is_alnum

string.is_alnum(s: String) -> Bool

Returns true if the first character is alphanumeric. Returns false for empty strings.

fn main() {
    println(string.is_alnum("a"))   // true
    println(string.is_alnum("3"))   // true
    println(string.is_alnum("!"))   // false
}

string.is_alpha

string.is_alpha(s: String) -> Bool

Returns true if the first character is alphabetic. Returns false for empty strings.

fn main() {
    println(string.is_alpha("a"))  // true
    println(string.is_alpha("1"))  // false
}

string.is_digit

string.is_digit(s: String) -> Bool

Returns true if the first character is an ASCII digit (0-9). Returns false for empty strings.

fn main() {
    println(string.is_digit("5"))  // true
    println(string.is_digit("a"))  // false
}

string.is_empty

string.is_empty(s: String) -> Bool

Returns true if the string has zero length.

fn main() {
    println(string.is_empty(""))     // true
    println(string.is_empty("hi"))   // false
}

string.is_lower

string.is_lower(s: String) -> Bool

Returns true if the first character is lowercase. Returns false for empty strings.

fn main() {
    println(string.is_lower("a"))  // true
    println(string.is_lower("A"))  // false
}

string.is_upper

string.is_upper(s: String) -> Bool

Returns true if the first character is uppercase. Returns false for empty strings.

fn main() {
    println(string.is_upper("A"))  // true
    println(string.is_upper("a"))  // false
}

string.is_whitespace

string.is_whitespace(s: String) -> Bool

Returns true if the first character is whitespace. Returns false for empty strings.

fn main() {
    println(string.is_whitespace(" "))   // true
    println(string.is_whitespace("a"))   // false
}

string.join

string.join(parts: List(String), separator: String) -> String

Joins a list of strings with a separator between each pair.

fn main() {
    let result = string.join(["a", "b", "c"], ", ")
    println(result)  // "a, b, c"
}

string.length

string.length(s: String) -> Int

Returns the byte length of the string.

fn main() {
    println(string.length("hello"))  // 5
}

string.pad_left

string.pad_left(s: String, width: Int, pad: String) -> String

Pads s on the left with the first character of pad until it reaches width. Returns s unchanged if already at or beyond width.

fn main() {
    println(string.pad_left("42", 5, "0"))  // "00042"
}

string.pad_right

string.pad_right(s: String, width: Int, pad: String) -> String

Pads s on the right with the first character of pad until it reaches width. Returns s unchanged if already at or beyond width.

fn main() {
    println(string.pad_right("hi", 5, "."))  // "hi..."
}

string.repeat

string.repeat(s: String, n: Int) -> String

Returns the string repeated n times. n must be non-negative.

fn main() {
    println(string.repeat("ab", 3))  // "ababab"
}

string.replace

string.replace(s: String, from: String, to: String) -> String

Replaces all occurrences of from with to.

fn main() {
    println(string.replace("hello world", "world", "silt"))
    // "hello silt"
}

string.slice

string.slice(s: String, start: Int, end: Int) -> String

Returns the substring from character index start (inclusive) to end (exclusive). Indices are clamped to the string length. Returns an empty string if start > end.

fn main() {
    println(string.slice("hello", 1, 4))  // "ell"
}

string.split

string.split(s: String, separator: String) -> List(String)

Splits the string on every occurrence of separator.

fn main() {
    let parts = string.split("a,b,c", ",")
    println(parts)  // ["a", "b", "c"]
}

string.starts_with

string.starts_with(s: String, prefix: String) -> Bool

Returns true if s starts with prefix.

fn main() {
    println(string.starts_with("hello", "hel"))  // true
}

string.to_lower

string.to_lower(s: String) -> String

Converts all characters to lowercase.

fn main() {
    println(string.to_lower("HELLO"))  // "hello"
}

string.to_upper

string.to_upper(s: String) -> String

Converts all characters to uppercase.

fn main() {
    println(string.to_upper("hello"))  // "HELLO"
}

string.trim

string.trim(s: String) -> String

Removes leading and trailing whitespace.

fn main() {
    println(string.trim("  hello  "))  // "hello"
}

string.trim_end

string.trim_end(s: String) -> String

Removes trailing whitespace only.

fn main() {
    println(string.trim_end("hello   "))  // "hello"
}

string.trim_start

string.trim_start(s: String) -> String

Removes leading whitespace only.

fn main() {
    println(string.trim_start("   hello"))  // "hello"
}

map

Functions for working with immutable, ordered maps (Map(k, v)). Maps use #{key: value} literal syntax. Keys must satisfy the Hash trait constraint.

Summary

FunctionSignatureDescription
contains(Map(k, v), k) -> BoolCheck if key exists
delete(Map(k, v), k) -> Map(k, v)Remove a key
each(Map(k, v), (k, v) -> ()) -> ()Iterate over all entries
entries(Map(k, v)) -> List((k, v))All key-value pairs as tuples
filter(Map(k, v), (k, v) -> Bool) -> Map(k, v)Keep entries matching predicate
from_entries(List((k, v))) -> Map(k, v)Build map from tuple list
get(Map(k, v), k) -> Option(v)Look up value by key
keys(Map(k, v)) -> List(k)All keys as a list
length(Map(k, v)) -> IntNumber of entries
map(Map(k, v), (k, v) -> (k2, v2)) -> Map(k2, v2)Transform all entries
merge(Map(k, v), Map(k, v)) -> Map(k, v)Merge two maps (right wins)
set(Map(k, v), k, v) -> Map(k, v)Insert or update a key
update(Map(k, v), k, v, (v) -> v) -> Map(k, v)Update existing or insert default
values(Map(k, v)) -> List(v)All values as a list

map.contains

map.contains(m: Map(k, v), key: k) -> Bool

Returns true if the map has an entry for key.

fn main() {
    let m = #{"a": 1, "b": 2}
    println(map.contains(m, "a"))  // true
    println(map.contains(m, "z"))  // false
}

map.delete

map.delete(m: Map(k, v), key: k) -> Map(k, v)

Returns a new map with key removed. No-op if key does not exist.

fn main() {
    let m = #{"a": 1, "b": 2}
    let m2 = map.delete(m, "a")
    println(map.length(m2))  // 1
}

map.each

map.each(m: Map(k, v), f: (k, v) -> ()) -> ()

Calls f with each key-value pair. Used for side effects.

fn main() {
    let m = #{"x": 10, "y": 20}
    map.each(m) { k, v -> println("{k} = {v}") }
}

map.entries

map.entries(m: Map(k, v)) -> List((k, v))

Returns all key-value pairs as a list of tuples.

fn main() {
    let m = #{"a": 1, "b": 2}
    let pairs = map.entries(m)
    // [("a", 1), ("b", 2)]
}

map.filter

map.filter(m: Map(k, v), f: (k, v) -> Bool) -> Map(k, v)

Returns a new map containing only entries where f returns true.

fn main() {
    let m = #{"a": 1, "b": 2, "c": 3}
    let big = map.filter(m) { k, v -> v > 1 }
    // #{"b": 2, "c": 3}
}

map.from_entries

map.from_entries(entries: List((k, v))) -> Map(k, v)

Builds a map from a list of (key, value) tuples. Later entries overwrite earlier ones with the same key.

fn main() {
    let m = map.from_entries([("a", 1), ("b", 2)])
    println(m)  // #{"a": 1, "b": 2}
}

map.get

map.get(m: Map(k, v), key: k) -> Option(v)

Returns Some(value) if the key exists, or None otherwise.

fn main() {
    let m = #{"name": "silt"}
    match map.get(m, "name") {
        Some(v) -> println(v)
        None -> println("not found")
    }
}

map.keys

map.keys(m: Map(k, v)) -> List(k)

Returns all keys as a list, in sorted order.

fn main() {
    let ks = map.keys(#{"b": 2, "a": 1})
    println(ks)  // ["a", "b"]
}

map.length

map.length(m: Map(k, v)) -> Int

Returns the number of entries in the map.

fn main() {
    println(map.length(#{"a": 1, "b": 2}))  // 2
}

map.map

map.map(m: Map(k, v), f: (k, v) -> (k2, v2)) -> Map(k2, v2)

Transforms each entry. The callback must return a (key, value) tuple.

fn main() {
    let m = #{"a": 1, "b": 2}
    let doubled = map.map(m) { k, v -> (k, v * 2) }
    // #{"a": 2, "b": 4}
}

map.merge

map.merge(m1: Map(k, v), m2: Map(k, v)) -> Map(k, v)

Merges two maps. When both have the same key, the value from m2 wins.

fn main() {
    let a = #{"x": 1, "y": 2}
    let b = #{"y": 99, "z": 3}
    let merged = map.merge(a, b)
    // #{"x": 1, "y": 99, "z": 3}
}

map.set

map.set(m: Map(k, v), key: k, value: v) -> Map(k, v)

Returns a new map with the key set to value. Inserts if new, overwrites if existing.

fn main() {
    let m = #{"a": 1}
    let m2 = map.set(m, "b", 2)
    println(m2)  // #{"a": 1, "b": 2}
}

map.update

map.update(m: Map(k, v), key: k, default: v, f: (v) -> v) -> Map(k, v)

If key exists, applies f to the current value. If key does not exist, applies f to default. Inserts the result.

fn main() {
    let m = #{"a": 1}
    let m2 = map.update(m, "a", 0) { v -> v + 10 }
    let m3 = map.update(m2, "b", 0) { v -> v + 10 }
    // m2 == #{"a": 11}
    // m3 == #{"a": 11, "b": 10}
}

map.values

map.values(m: Map(k, v)) -> List(v)

Returns all values as a list, in key-sorted order.

fn main() {
    let vs = map.values(#{"a": 1, "b": 2})
    println(vs)  // [1, 2]
}

set

Functions for working with immutable, ordered sets (Set(a)). Sets use #[...] literal syntax and contain unique values.

Summary

FunctionSignatureDescription
contains(Set(a), a) -> BoolCheck membership
difference(Set(a), Set(a)) -> Set(a)Elements in first but not second
each(Set(a), (a) -> ()) -> ()Iterate over all elements
filter(Set(a), (a) -> Bool) -> Set(a)Keep elements matching predicate
fold(Set(a), b, (b, a) -> b) -> bReduce to a single value
from_list(List(a)) -> Set(a)Create set from list
insert(Set(a), a) -> Set(a)Add an element
intersection(Set(a), Set(a)) -> Set(a)Elements in both sets
is_subset(Set(a), Set(a)) -> BoolTrue if first is subset of second
length(Set(a)) -> IntNumber of elements
map(Set(a), (a) -> b) -> Set(b)Transform each element
new() -> Set(a)Create an empty set
remove(Set(a), a) -> Set(a)Remove an element
to_list(Set(a)) -> List(a)Convert set to sorted list
union(Set(a), Set(a)) -> Set(a)Combine all elements

set.contains

set.contains(s: Set(a), elem: a) -> Bool

Returns true if elem is in the set.

fn main() {
    let s = #[1, 2, 3]
    println(set.contains(s, 2))  // true
    println(set.contains(s, 5))  // false
}

set.difference

set.difference(a: Set(a), b: Set(a)) -> Set(a)

Returns elements that are in a but not in b.

fn main() {
    let result = set.difference(#[1, 2, 3], #[2, 3, 4])
    println(set.to_list(result))  // [1]
}

set.each

set.each(s: Set(a), f: (a) -> ()) -> ()

Calls f for every element. Used for side effects.

fn main() {
    set.each(#[1, 2, 3]) { x -> println(x) }
}

set.filter

set.filter(s: Set(a), f: (a) -> Bool) -> Set(a)

Returns a new set containing only elements for which f returns true.

fn main() {
    let evens = set.filter(#[1, 2, 3, 4]) { x -> x % 2 == 0 }
    println(set.to_list(evens))  // [2, 4]
}

set.fold

set.fold(s: Set(a), init: b, f: (b, a) -> b) -> b

Reduces the set to a single value. Iteration order is sorted.

fn main() {
    let sum = set.fold(#[1, 2, 3], 0) { acc, x -> acc + x }
    println(sum)  // 6
}

set.from_list

set.from_list(xs: List(a)) -> Set(a)

Creates a set from a list, removing duplicates.

fn main() {
    let s = set.from_list([1, 2, 2, 3])
    println(set.length(s))  // 3
}

set.insert

set.insert(s: Set(a), elem: a) -> Set(a)

Returns a new set with elem added. No-op if already present.

fn main() {
    let s = set.insert(#[1, 2], 3)
    println(set.to_list(s))  // [1, 2, 3]
}

set.intersection

set.intersection(a: Set(a), b: Set(a)) -> Set(a)

Returns elements that are in both a and b.

fn main() {
    let result = set.intersection(#[1, 2, 3], #[2, 3, 4])
    println(set.to_list(result))  // [2, 3]
}

set.is_subset

set.is_subset(a: Set(a), b: Set(a)) -> Bool

Returns true if every element of a is also in b.

fn main() {
    println(set.is_subset(#[1, 2], #[1, 2, 3]))  // true
    println(set.is_subset(#[1, 4], #[1, 2, 3]))  // false
}

set.length

set.length(s: Set(a)) -> Int

Returns the number of elements in the set.

fn main() {
    println(set.length(#[1, 2, 3]))  // 3
}

set.map

set.map(s: Set(a), f: (a) -> b) -> Set(b)

Returns a new set with f applied to each element. The result set may be smaller if f maps distinct elements to the same value.

fn main() {
    let result = set.map(#[1, 2, 3]) { x -> x * 10 }
    println(set.to_list(result))  // [10, 20, 30]
}

set.new

set.new() -> Set(a)

Creates a new empty set.

fn main() {
    let s = set.new()
    let s = set.insert(s, 42)
    println(set.length(s))  // 1
}

set.remove

set.remove(s: Set(a), elem: a) -> Set(a)

Returns a new set with elem removed. No-op if not present.

fn main() {
    let s = set.remove(#[1, 2, 3], 2)
    println(set.to_list(s))  // [1, 3]
}

set.to_list

set.to_list(s: Set(a)) -> List(a)

Converts the set to a sorted list.

fn main() {
    let xs = set.to_list(#[3, 1, 2])
    println(xs)  // [1, 2, 3]
}

set.union

set.union(a: Set(a), b: Set(a)) -> Set(a)

Returns a set containing all elements from both a and b.

fn main() {
    let result = set.union(#[1, 2], #[2, 3])
    println(set.to_list(result))  // [1, 2, 3]
}

int

Functions for parsing, converting, and comparing integers.

Summary

FunctionSignatureDescription
abs(Int) -> IntAbsolute value
max(Int, Int) -> IntLarger of two values
min(Int, Int) -> IntSmaller of two values
parse(String) -> Result(Int, String)Parse string to integer
to_float(Int) -> FloatConvert to float
to_string(Int) -> StringConvert to string

int.abs

int.abs(n: Int) -> Int

Returns the absolute value.

fn main() {
    println(int.abs(-42))  // 42
    println(int.abs(7))    // 7
}

int.max

int.max(a: Int, b: Int) -> Int

Returns the larger of two integers.

fn main() {
    println(int.max(3, 7))  // 7
}

int.min

int.min(a: Int, b: Int) -> Int

Returns the smaller of two integers.

fn main() {
    println(int.min(3, 7))  // 3
}

int.parse

int.parse(s: String) -> Result(Int, String)

Parses a string as an integer. Leading/trailing whitespace is trimmed. Returns Ok(n) on success, Err(message) on failure.

fn main() {
    match int.parse("42") {
        Ok(n) -> println(n)
        Err(e) -> println("parse error: {e}")
    }
}

int.to_float

int.to_float(n: Int) -> Float

Converts an integer to a float.

fn main() {
    let f = int.to_float(42)
    println(f)  // 42.0
}

int.to_string

int.to_string(n: Int) -> String

Converts an integer to its string representation.

fn main() {
    let s = int.to_string(42)
    println(s)  // "42"
}

float

Functions for parsing, rounding, converting, and comparing floats.

Note: round, ceil, and floor return Float, not Int. Use float.to_int to convert the result to an integer.

Summary

FunctionSignatureDescription
abs(Float) -> FloatAbsolute value
ceil(Float) -> FloatRound up to nearest integer (as Float)
floor(Float) -> FloatRound down to nearest integer (as Float)
max(Float, Float) -> FloatLarger of two values
min(Float, Float) -> FloatSmaller of two values
parse(String) -> Result(Float, String)Parse string to float
round(Float) -> FloatRound to nearest integer (as Float)
to_int(Float) -> IntTruncate to integer
to_string(Float, Int) -> StringFormat with decimal places

float.abs

float.abs(f: Float) -> Float

Returns the absolute value.

fn main() {
    println(float.abs(-3.14))  // 3.14
}

float.ceil

float.ceil(f: Float) -> Float

Rounds up to the nearest integer, returned as a Float.

fn main() {
    println(float.ceil(3.2))   // 4.0
    println(float.ceil(-3.2))  // -3.0
}

float.floor

float.floor(f: Float) -> Float

Rounds down to the nearest integer, returned as a Float.

fn main() {
    println(float.floor(3.9))   // 3.0
    println(float.floor(-3.2))  // -4.0
}

float.max

float.max(a: Float, b: Float) -> Float

Returns the larger of two floats.

fn main() {
    println(float.max(1.5, 2.5))  // 2.5
}

float.min

float.min(a: Float, b: Float) -> Float

Returns the smaller of two floats.

fn main() {
    println(float.min(1.5, 2.5))  // 1.5
}

float.parse

float.parse(s: String) -> Result(Float, String)

Parses a string as a float. Leading/trailing whitespace is trimmed. Returns Ok(f) on success, Err(message) on failure.

fn main() {
    match float.parse("3.14") {
        Ok(f) -> println(f)
        Err(e) -> println("error: {e}")
    }
}

float.round

float.round(f: Float) -> Float

Rounds to the nearest integer, returned as a Float. Ties round away from zero.

fn main() {
    println(float.round(3.6))  // 4.0
    println(float.round(3.4))  // 3.0
}

float.to_int

float.to_int(f: Float) -> Int

Truncates toward zero, converting to an integer.

fn main() {
    println(float.to_int(3.9))   // 3
    println(float.to_int(-3.9))  // -3
}

float.to_string

float.to_string(f: Float, decimals: Int) -> String

Formats a float as a string with exactly decimals decimal places. The decimals argument is required and must be non-negative.

fn main() {
    println(float.to_string(3.14159, 2))  // "3.14"
    println(float.to_string(42.0, 0))     // "42"
}

result

Functions for transforming and querying Result(a, e) values without pattern matching.

Summary

FunctionSignatureDescription
flat_map(Result(a, e), (a) -> Result(b, e)) -> Result(b, e)Chain fallible operations
flatten(Result(Result(a, e), e)) -> Result(a, e)Remove one nesting level
is_err(Result(a, e)) -> BoolTrue if Err
is_ok(Result(a, e)) -> BoolTrue if Ok
map_err(Result(a, e), (e) -> f) -> Result(a, f)Transform the error
map_ok(Result(a, e), (a) -> b) -> Result(b, e)Transform the success value
unwrap_or(Result(a, e), a) -> aExtract value or use default

result.flat_map

result.flat_map(r: Result(a, e), f: (a) -> Result(b, e)) -> Result(b, e)

If r is Ok(v), calls f(v) and returns its result. If r is Err, returns the Err unchanged. Useful for chaining fallible operations.

fn main() {
    let r = Ok("42")
        |> result.flat_map { s -> int.parse(s) }
    println(r)  // Ok(42)
}

result.flatten

result.flatten(r: Result(Result(a, e), e)) -> Result(a, e)

Collapses a nested Result. Ok(Ok(v)) becomes Ok(v), Ok(Err(e)) becomes Err(e), and Err(e) stays Err(e).

fn main() {
    println(result.flatten(Ok(Ok(42))))         // Ok(42)
    println(result.flatten(Ok(Err("oops"))))    // Err("oops")
}

result.is_err

result.is_err(r: Result(a, e)) -> Bool

Returns true if the result is an Err.

fn main() {
    println(result.is_err(Err("fail")))  // true
    println(result.is_err(Ok(42)))       // false
}

result.is_ok

result.is_ok(r: Result(a, e)) -> Bool

Returns true if the result is an Ok.

fn main() {
    println(result.is_ok(Ok(42)))       // true
    println(result.is_ok(Err("fail")))  // false
}

result.map_err

result.map_err(r: Result(a, e), f: (e) -> f) -> Result(a, f)

If r is Err(e), returns Err(f(e)). If r is Ok, returns it unchanged.

fn main() {
    let r = Err("not found") |> result.map_err { e -> "Error: {e}" }
    println(r)  // Err("Error: not found")
}

result.map_ok

result.map_ok(r: Result(a, e), f: (a) -> b) -> Result(b, e)

If r is Ok(v), returns Ok(f(v)). If r is Err, returns it unchanged.

fn main() {
    let r = Ok(21) |> result.map_ok { n -> n * 2 }
    println(r)  // Ok(42)
}

result.unwrap_or

result.unwrap_or(r: Result(a, e), default: a) -> a

Returns the Ok value, or default if the result is Err.

fn main() {
    println(result.unwrap_or(Ok(42), 0))        // 42
    println(result.unwrap_or(Err("fail"), 0))    // 0
}

option

Functions for transforming and querying Option(a) values without pattern matching.

Summary

FunctionSignatureDescription
flat_map(Option(a), (a) -> Option(b)) -> Option(b)Chain optional operations
is_none(Option(a)) -> BoolTrue if None
is_some(Option(a)) -> BoolTrue if Some
map(Option(a), (a) -> b) -> Option(b)Transform the inner value
to_result(Option(a), e) -> Result(a, e)Convert to Result with error value
unwrap_or(Option(a), a) -> aExtract value or use default

option.flat_map

option.flat_map(opt: Option(a), f: (a) -> Option(b)) -> Option(b)

If opt is Some(v), calls f(v) and returns its result. If opt is None, returns None.

fn main() {
    let result = Some(42) |> option.flat_map { n ->
        when n > 0 -> Some(n * 2)
        else -> None
    }
    println(result)  // Some(84)
}

option.is_none

option.is_none(opt: Option(a)) -> Bool

Returns true if the option is None.

fn main() {
    println(option.is_none(None))      // true
    println(option.is_none(Some(1)))   // false
}

option.is_some

option.is_some(opt: Option(a)) -> Bool

Returns true if the option is Some.

fn main() {
    println(option.is_some(Some(1)))   // true
    println(option.is_some(None))      // false
}

option.map

option.map(opt: Option(a), f: (a) -> b) -> Option(b)

If opt is Some(v), returns Some(f(v)). If opt is None, returns None.

fn main() {
    let result = Some(21) |> option.map { n -> n * 2 }
    println(result)  // Some(42)
}

option.to_result

option.to_result(opt: Option(a), error: e) -> Result(a, e)

Converts Some(v) to Ok(v) and None to Err(error).

fn main() {
    let r = option.to_result(Some(42), "missing")
    println(r)  // Ok(42)

    let r2 = option.to_result(None, "missing")
    println(r2)  // Err("missing")
}

option.unwrap_or

option.unwrap_or(opt: Option(a), default: a) -> a

Returns the inner value if Some, otherwise returns default.

fn main() {
    println(option.unwrap_or(Some(42), 0))  // 42
    println(option.unwrap_or(None, 0))      // 0
}

io

Functions for file I/O, stdin, command-line arguments, and debug inspection.

Summary

FunctionSignatureDescription
args() -> List(String)Command-line arguments
inspect(a) -> StringDebug representation of any value
read_file(String) -> Result(String, String)Read entire file as string
read_line() -> Result(String, String)Read one line from stdin
write_file(String, String) -> Result((), String)Write string to file

io.args

io.args() -> List(String)

Returns the command-line arguments as a list of strings, including the program name.

fn main() {
    let args = io.args()
    list.each(args) { a -> println(a) }
}

io.inspect

io.inspect(value: a) -> String

Returns a debug-style string representation of any value, using silt syntax (e.g., strings include quotes, lists show brackets).

fn main() {
    let s = io.inspect([1, "hello", true])
    println(s)  // [1, "hello", true]
}

io.read_file

io.read_file(path: String) -> Result(String, String)

Reads the entire contents of a file. Returns Ok(contents) on success or Err(message) on failure.

fn main() {
    match io.read_file("data.txt") {
        Ok(contents) -> println(contents)
        Err(e) -> println("Error: {e}")
    }
}

io.read_line

io.read_line() -> Result(String, String)

Reads a single line from stdin (trailing newline stripped). Returns Ok(line) on success or Err(message) on failure.

fn main() {
    print("Name: ")
    match io.read_line() {
        Ok(name) -> println("Hello, {name}!")
        Err(e) -> println("Error: {e}")
    }
}

io.write_file

io.write_file(path: String, contents: String) -> Result((), String)

Writes a string to a file, creating or overwriting it. Returns Ok(()) on success or Err(message) on failure.

fn main() {
    match io.write_file("output.txt", "hello") {
        Ok(_) -> println("written")
        Err(e) -> println("Error: {e}")
    }
}

fs

Filesystem path queries.

Summary

FunctionSignatureDescription
exists(String) -> BoolCheck if path exists

fs.exists

fs.exists(path: String) -> Bool

Returns true if the file or directory at path exists.

fn main() {
    when fs.exists("config.toml") -> println("found config")
    else -> println("no config")
}

test

Assertion functions for test scripts. Each accepts an optional trailing String message argument.

Summary

FunctionSignatureDescription
assert(Bool, String?) -> ()Assert value is truthy
assert_eq(a, a, String?) -> ()Assert two values are equal
assert_ne(a, a, String?) -> ()Assert two values are not equal

test.assert

test.assert(condition: Bool) -> ()
test.assert(condition: Bool, message: String) -> ()

Panics if condition is false. The optional message is included in the error.

fn main() {
    test.assert(1 + 1 == 2)
    test.assert(1 + 1 == 2, "math should work")
}

test.assert_eq

test.assert_eq(left: a, right: a) -> ()
test.assert_eq(left: a, right: a, message: String) -> ()

Panics if left != right, displaying both values.

fn main() {
    test.assert_eq(list.length([1, 2, 3]), 3)
    test.assert_eq(1 + 1, 2, "addition")
}

test.assert_ne

test.assert_ne(left: a, right: a) -> ()
test.assert_ne(left: a, right: a, message: String) -> ()

Panics if left == right, displaying both values.

fn main() {
    test.assert_ne("hello", "world")
}

regex

Regular expression functions. Pattern strings use standard regex syntax.

Summary

FunctionSignatureDescription
captures(String, String) -> Option(List(String))Capture groups from first match
captures_all(String, String) -> List(List(String))Capture groups from all matches
find(String, String) -> Option(String)First match
find_all(String, String) -> List(String)All matches
is_match(String, String) -> BoolTest if pattern matches
replace(String, String, String) -> StringReplace first match
replace_all(String, String, String) -> StringReplace all matches
replace_all_with(String, String, (String) -> String) -> StringReplace all with callback
split(String, String) -> List(String)Split on pattern

regex.captures

regex.captures(pattern: String, text: String) -> Option(List(String))

Returns capture groups from the first match, or None if no match. The full match is at index 0, followed by numbered groups.

fn main() {
    match regex.captures("(\\w+)@(\\w+)", "user@host") {
        Some(groups) -> {
            println(list.get(groups, 1))  // Some("user")
            println(list.get(groups, 2))  // Some("host")
        }
        None -> println("no match")
    }
}

regex.captures_all

regex.captures_all(pattern: String, text: String) -> List(List(String))

Returns capture groups for every match. Each inner list has the full match at index 0 followed by numbered groups.

fn main() {
    let results = regex.captures_all("(\\d+)-(\\d+)", "1-2 and 3-4")
    // [["1-2", "1", "2"], ["3-4", "3", "4"]]
}

regex.find

regex.find(pattern: String, text: String) -> Option(String)

Returns Some(matched_text) for the first match, or None.

fn main() {
    let result = regex.find("\\d+", "abc 123 def")
    println(result)  // Some("123")
}

regex.find_all

regex.find_all(pattern: String, text: String) -> List(String)

Returns all non-overlapping matches as a list of strings.

fn main() {
    let nums = regex.find_all("\\d+", "a1 b22 c333")
    println(nums)  // ["1", "22", "333"]
}

regex.is_match

regex.is_match(pattern: String, text: String) -> Bool

Returns true if the pattern matches anywhere in the text.

fn main() {
    println(regex.is_match("^\\d+$", "123"))    // true
    println(regex.is_match("^\\d+$", "abc"))    // false
}

regex.replace

regex.replace(pattern: String, text: String, replacement: String) -> String

Replaces the first match with the replacement string.

fn main() {
    let result = regex.replace("\\d+", "abc 123 def 456", "NUM")
    println(result)  // "abc NUM def 456"
}

regex.replace_all

regex.replace_all(pattern: String, text: String, replacement: String) -> String

Replaces all matches with the replacement string.

fn main() {
    let result = regex.replace_all("\\d+", "abc 123 def 456", "NUM")
    println(result)  // "abc NUM def NUM"
}

regex.replace_all_with

regex.replace_all_with(pattern: String, text: String, f: (String) -> String) -> String

Replaces all matches by calling f with each matched text. The callback must return a string.

fn main() {
    let result = regex.replace_all_with("\\d+", "a1 b22 c333") { m ->
        int.to_string(int.parse(m) |> result.unwrap_or(0) |> fn(n) { n * 2 })
    }
    // "a2 b44 c666"
}

regex.split

regex.split(pattern: String, text: String) -> List(String)

Splits the text on every occurrence of the pattern.

fn main() {
    let parts = regex.split("\\s+", "hello   world   silt")
    println(parts)  // ["hello", "world", "silt"]
}

json

Parse JSON strings into typed silt values and serialize values to JSON.

Summary

FunctionSignatureDescription
parse(Type, String) -> Result(T, String)Parse JSON object into record
parse_list(Type, String) -> Result(List(T), String)Parse JSON array into record list
parse_map(Type, String) -> Result(Map(String, v), String)Parse JSON object into map
pretty(a) -> StringPretty-print value as JSON
stringify(a) -> StringSerialize value as compact JSON

json.parse

json.parse(T: Type, s: String) -> Result(T, String)

Parses a JSON string into a record of type T. The first argument is a record type name (not a string). Fields are matched by name; Option fields default to None if missing from the JSON.

type User {
    name: String,
    age: Int,
}

fn main() {
    let json = "{\"name\": \"Alice\", \"age\": 30}"
    match json.parse(User, json) {
        Ok(user) -> println(user.name)
        Err(e) -> println("Error: {e}")
    }
}

json.parse_list

json.parse_list(T: Type, s: String) -> Result(List(T), String)

Parses a JSON array where each element is a record of type T.

type Point {
    x: Int,
    y: Int,
}

fn main() {
    let json = "[{\"x\": 1, \"y\": 2}, {\"x\": 3, \"y\": 4}]"
    match json.parse_list(Point, json) {
        Ok(points) -> list.each(points) { p -> println("{p.x}, {p.y}") }
        Err(e) -> println("Error: {e}")
    }
}

json.parse_map

json.parse_map(V: Type, s: String) -> Result(Map(String, V), String)

Parses a JSON object into a Map(String, V). The first argument is a type descriptor (Int, Float, String, Bool, or a record type).

fn main() {
    let json = "{\"x\": 10, \"y\": 20}"
    match json.parse_map(Int, json) {
        Ok(m) -> println(map.get(m, "x"))  // Some(10)
        Err(e) -> println("Error: {e}")
    }
}

json.pretty

json.pretty(value: a) -> String

Serializes any value to a pretty-printed JSON string (with indentation and newlines).

fn main() {
    let data = #{"name": "silt", "version": 1}
    println(json.pretty(data))
}

json.stringify

json.stringify(value: a) -> String

Serializes any value to a compact JSON string.

fn main() {
    let data = #{"key": [1, 2, 3]}
    println(json.stringify(data))
    // {"key":[1,2,3]}
}

math

Mathematical functions and constants. All functions operate on Float values.

Summary

NameSignatureDescription
acos(Float) -> FloatArccosine (radians)
asin(Float) -> FloatArcsine (radians)
atan(Float) -> FloatArctangent (radians)
atan2(Float, Float) -> FloatTwo-argument arctangent
cos(Float) -> FloatCosine
eFloatEuler’s number (2.71828…)
log(Float) -> FloatNatural logarithm (ln)
log10(Float) -> FloatBase-10 logarithm
piFloatPi (3.14159…)
pow(Float, Float) -> FloatExponentiation
sin(Float) -> FloatSine
sqrt(Float) -> FloatSquare root
tan(Float) -> FloatTangent

math.acos

math.acos(x: Float) -> Float

Returns the arccosine of x in radians.

fn main() {
    println(math.acos(1.0))  // 0.0
}

math.asin

math.asin(x: Float) -> Float

Returns the arcsine of x in radians.

fn main() {
    println(math.asin(1.0))  // 1.5707... (pi/2)
}

math.atan

math.atan(x: Float) -> Float

Returns the arctangent of x in radians.

fn main() {
    println(math.atan(1.0))  // 0.7853... (pi/4)
}

math.atan2

math.atan2(y: Float, x: Float) -> Float

Returns the angle in radians between the positive x-axis and the point (x, y). Handles all quadrants correctly.

fn main() {
    println(math.atan2(1.0, 1.0))  // 0.7853... (pi/4)
}

math.cos

math.cos(x: Float) -> Float

Returns the cosine of x (in radians).

fn main() {
    println(math.cos(0.0))       // 1.0
    println(math.cos(math.pi))   // -1.0
}

math.e

math.e : Float

Euler’s number, approximately 2.718281828459045. This is a constant, not a function.

fn main() {
    println(math.e)  // 2.718281828459045
}

math.log

math.log(x: Float) -> Float

Returns the natural logarithm (base e) of x.

fn main() {
    println(math.log(math.e))  // 1.0
    println(math.log(1.0))     // 0.0
}

math.log10

math.log10(x: Float) -> Float

Returns the base-10 logarithm of x.

fn main() {
    println(math.log10(100.0))  // 2.0
}

math.pi

math.pi : Float

Pi, approximately 3.141592653589793. This is a constant, not a function.

fn main() {
    let circumference = 2.0 * math.pi * 5.0
    println(circumference)
}

math.pow

math.pow(base: Float, exponent: Float) -> Float

Returns base raised to the power of exponent.

fn main() {
    println(math.pow(2.0, 10.0))  // 1024.0
}

math.sin

math.sin(x: Float) -> Float

Returns the sine of x (in radians).

fn main() {
    println(math.sin(0.0))           // 0.0
    println(math.sin(math.pi / 2.0)) // 1.0
}

math.sqrt

math.sqrt(x: Float) -> Float

Returns the square root of x.

fn main() {
    println(math.sqrt(4.0))   // 2.0
    println(math.sqrt(2.0))   // 1.4142...
}

math.tan

math.tan(x: Float) -> Float

Returns the tangent of x (in radians).

fn main() {
    println(math.tan(0.0))           // 0.0
    println(math.tan(math.pi / 4.0)) // 1.0 (approximately)
}

channel

Bounded channels for cooperative concurrency. Channels provide communication between tasks spawned with task.spawn.

Summary

FunctionSignatureDescription
close(Channel) -> ()Close the channel
each(Channel, (a) -> b) -> ()Iterate until channel closes
new(Int) -> ChannelCreate a bounded channel
receive(Channel) -> ChannelResult(a)Blocking receive
select(List(Channel)) -> (Channel, a)Wait on multiple channels
send(Channel, a) -> ()Blocking send
try_receive(Channel) -> ChannelResult(a)Non-blocking receive
try_send(Channel, a) -> BoolNon-blocking send

channel.close

channel.close(ch: Channel) -> ()

Closes the channel. Subsequent sends will fail. Receivers will see Closed after all buffered messages are consumed.

fn main() {
    let ch = channel.new(10)
    channel.send(ch, 1)
    channel.close(ch)
}

channel.each

channel.each(ch: Channel, f: (a) -> b) -> ()

Receives messages from the channel and calls f with each one, until the channel is closed. This is the idiomatic way to consume all messages.

fn main() {
    let ch = channel.new(10)
    task.spawn(fn() {
        channel.send(ch, 1)
        channel.send(ch, 2)
        channel.close(ch)
    })
    channel.each(ch) { msg -> println(msg) }
    // prints 1, then 2
}

channel.new

channel.new(capacity: Int) -> Channel

Creates a new bounded channel with the given buffer capacity. Sends block when the buffer is full; receives block when the buffer is empty.

fn main() {
    let ch = channel.new(10)
}

channel.receive

channel.receive(ch: Channel) -> ChannelResult(a)

Receives a value from the channel. Returns Message(value) when a value is available, or Closed when the channel is closed and empty. Cooperatively yields to other tasks while waiting.

fn main() {
    let ch = channel.new(1)
    channel.send(ch, 42)
    match channel.receive(ch) {
        Message(v) -> println(v)
        Closed -> println("done")
    }
}

channel.select

channel.select(channels: List(Channel)) -> (Channel, a)

Waits until one of the channels has a message ready. Returns a tuple of (channel, value). Cooperatively yields while waiting.

fn main() {
    let ch1 = channel.new(1)
    let ch2 = channel.new(1)
    task.spawn(fn() { channel.send(ch2, "hello") })
    let (ch, val) = channel.select([ch1, ch2])
    println(val)  // "hello"
}

channel.send

channel.send(ch: Channel, value: a) -> ()

Sends a value into the channel. Blocks (cooperatively yields) if the buffer is full.

fn main() {
    let ch = channel.new(1)
    channel.send(ch, "hello")
}

channel.try_receive

channel.try_receive(ch: Channel) -> ChannelResult(a)

Non-blocking receive. Returns Message(value) if a value is immediately available, Empty if the channel is open but has no data, or Closed if the channel is closed and empty.

fn main() {
    let ch = channel.new(1)
    match channel.try_receive(ch) {
        Message(v) -> println(v)
        Empty -> println("nothing yet")
        Closed -> println("done")
    }
}

channel.try_send

channel.try_send(ch: Channel, value: a) -> Bool

Non-blocking send. Returns true if the value was successfully buffered, false if the buffer is full or the channel is closed.

fn main() {
    let ch = channel.new(1)
    let ok = channel.try_send(ch, 42)
    println(ok)  // true
}

task

Spawn and coordinate concurrent tasks. Tasks run in parallel and communicate through channels.

Summary

FunctionSignatureDescription
cancel(Handle) -> ()Cancel a running task
join(Handle) -> aWait for a task to complete
spawn(() -> a) -> HandleSpawn a new cooperative task

task.cancel

task.cancel(handle: Handle) -> ()

Cancels a running task. The task will not execute further. No-op if the task has already completed.

fn main() {
    let h = task.spawn(fn() {
        // long-running work
    })
    task.cancel(h)
}

task.join

task.join(handle: Handle) -> a

Blocks until the task completes and returns its result. Cooperatively yields while waiting.

fn main() {
    let h = task.spawn(fn() { 1 + 2 })
    let result = task.join(h)
    println(result)  // 3
}

task.spawn

task.spawn(f: () -> a) -> Handle

Spawns a zero-argument function as a cooperative task. Returns a handle that can be used with task.join or task.cancel.

fn main() {
    let h = task.spawn(fn() {
        println("running in a task")
        42
    })
    let result = task.join(h)
    println(result)  // 42
}