Reference: The Standard Library
Reference material — dip in as needed.
Lists
List<T> is the growable collection. Build one from an array and transform it
with map, filter, and fold:
fun main() {
let nums := List::from([1, 2, 3, 4, 5]);
fun double(x: i64) -> i64 { x * 2 }
fun is_even(x: i64) -> boolean { x % 2 == 0 }
fun add(acc: i64, x: i64) -> i64 { acc + x }
let doubled := nums.map(double);
let evens := nums.filter(is_even);
let sum := nums.fold(0i64, add);
println(sum); // 15
println(evens.len()); // 2
println(doubled.get(0).unwrap_or(0)); // 2
}
map may change the element type, and the transforms chain:
let total: i64 := List::from([1, 2, 3, 4])
.filter(|x: i64| -> boolean { x % 2 == 1 })
.map(|x: i64| -> i64 { x * 10 })
.fold(0i64, |a: i64, x: i64| -> i64 { a + x }); // 40
find returns the first matching element as a Perhaps, and concat joins two
lists. push, pop, get, and len round out the collection.
Perhaps and Result
Perhaps<T> (a value or nothing) and Result<T, E> (a success or an error) are
the core optional and fallible types. Rather than always reaching for match,
use their combinators:
fun main() {
let maybe := Perhaps::Some { value = 21 };
fun double(x: i64) -> i64 { x * 2 }
// Transform inside the Perhaps, then supply a fallback.
let doubled := maybe.map(double).unwrap_or(0); // 42
let nothing: Perhaps<i64> := None;
println(nothing.is_none()); // true
println(nothing.unwrap_or(7)); // 7
}
Result works the same way, with is_ok/is_err and map/and_then carrying
the Err through untouched:
let r: Result<i64, String> := Ok { value = 10 };
let n := r.map(|x: i64| -> i64 { x + 5 }).unwrap_or(0); // 15
Strings
Strings carry a full method surface. Every index counts Unicode scalar
values (just like len), and the operations are total — an out-of-range index
clamps or returns None instead of panicking:
fun main() {
let line := " Hello, World ";
println(line.trim()); // "Hello, World"
println("abc".to_upper()); // "ABC"
println("hello".contains("ell")); // true
println("a,b,c".split(",").len()); // 3
println("ab".repeat(3)); // "ababab"
println(String::join(["a", "b", "c"], "-")); // "a-b-c"
match ("hello".index_of("l")) {
Some { value } => println(value), // 2
_ => println("not found"),
}
}
Files
std::fs provides text-oriented file operations. They return
Result<_, OsError>, so handle the error case explicitly:
import std::fs::{write_string, read_to_string};
fun main() {
match (write_string("/tmp/greeting.txt", "hello")) {
Ok { value } => {},
Err { error } => println(error.to_string()),
}
let contents := read_to_string("/tmp/greeting.txt").unwrap_or("");
println(contents); // hello
}
OsError implements Display, so error.to_string() (or error.message())
gives a readable description. Alongside reading and writing, std::fs offers
append_string, exists, read_dir, and the create_dir* / remove_*
family.
Environment and processes
std::env reads the process environment:
import std::env::get;
fun main() {
match (get("HOME")) {
Some { value } => println(value),
_ => println("HOME is not set"),
}
}
std::process runs other programs. The API is shell-free — you pass the command
and its arguments separately, so quoting and shell expansion never apply:
import std::process::run;
fun main() {
match (run("echo", ["hello", "world"])) {
Ok { value } => println(value.stdout),
Err { error } => println(error.to_string()),
}
}
A non-zero exit status is a normal Ok result (inspect value.status); only a
failure to launch the command is an Err.
Where things live
Everything under "Lists", "Perhaps and Result", and "Strings" is in std::core
and needs no import. The host modules — std::env, std::fs, std::process —
must be imported explicitly, the same as any other module. See the
Runtime reference for the complete signatures.