Standard Library Reference
Canonical built-in reference aligned with interpreter/builtins_*.go.
Karl is expression-based, functions-first, and concurrency-native.
Streams/processes are major features, but part of a broader language model.
1. Language Model
These are language forms (not regular built-ins):
if / match / for are expressions (produce values).
spawn and & start tasks.
race and !& race tasks.
wait awaits <task> and <process>.
| composes stream sources, stages, and sinks.
2. Runtime Availability
| Feature | CLI / Native | Bench / WASM |
| Core language + collections + strings + math | Yes | Yes |
| Tasks/channels + stream algebra on in-memory/channel/http sources | Yes | Yes |
Filesystem (readFile, writeFile, read, writer, ...) | Yes | No |
Process API (proc, run, exec sink) | Yes | No |
SQL + signals + httpServe | Yes | No |
3. Prebound Constants
| Name | Value | Used for |
PIPE | "pipe" | Process stdio mode |
INHERIT | "inherit" | Process stdio mode |
NULL | "null" | Process stdio mode |
TEXT | "text" | Stream mode |
BYTES | "bytes" | Stream mode |
4. Core Runtime
| Name | Signature | Return | Notes |
log | log(...values) | () | Print inspected values. |
logt | logt(...values) | () | Prefixes RFC3339 UTC timestamp. |
str | str(value) | String | Value stringification. |
sleep | sleep(ms) | () | Cooperative delay in milliseconds. |
fail | fail([message]) | recoverable error | Recover with ? { ... }. |
exit | exit([message]) | never | Terminates execution. |
5. Concurrency Helpers (Built-ins)
| Name | Signature | Return | Notes |
channel | channel() | Channel | Alias of rendezvous(). |
rendezvous | rendezvous() | Channel | Unbuffered channel. |
buffered | buffered(size) | Channel | Buffered channel. |
send | send(ch, value) or send(ch) | () or stream sink | send(ch) drains stream into channel. |
recv | recv(ch) | [value|null, doneBool] | Also ch.recv(). |
done | done(ch) | () | Also ch.done(). |
then | then(task, fn) | Task | Also task.then(fn). |
6. Program Runtime
| Name | Signature | Return | Notes |
argv | argv() | Array<String> | Arguments after -- with karl run. |
programPath | programPath() | String|null | Current script path. |
environ | environ() | Array<String> | KEY=value entries. |
env | env(name) | String|null | Single lookup. |
readLine | readLine() | String|null | Reads one line from stdin. |
7. Collections
Karl has four collection families: Array, Map, Set,
ordered tree, and hierarchical ntree.
7.1 Constructors and Core Shapes
| Name | Signature | Return | Notes |
map | map() or map(array, fn) or map(fn) | Map / Array / stream stage | Overloaded constructor + transform + stage. |
set | set(), set(array), set(map,key,value) | Set / Map | Overloaded constructor + map update. |
tree | tree(kind?) | Tree | kind is "avl" or "treap". |
ntree | ntree(rootId, rootValue?) | NTree | Hierarchical tree with stable node IDs. |
len | len(string|bytes|array|map|set|object) | Int | For sets, use .size property if preferred. |
7.2 Map and Set Operations
| Name | Signature | Return | Notes |
get | get(map, key) | Value|null | Map lookup only. |
add | add(set, value) | Set | Mutates set. |
has | has(mapOrSet, key) | Bool | - |
delete | delete(mapOrSet, key) | Bool | - |
keys | keys(mapOrObject) | Array | - |
values | values(mapOrSet) | Array | - |
7.3 Ordered Tree: tree(kind?)
Ordered key-value index (sorted by key). Key domain is homogeneous:
int, float, string, or char.
| Method | Signature | Return |
set | t.set(key, value) | Tree |
get | t.get(key) | Value|null |
has | t.has(key) | Bool |
delete | t.delete(key) | Bool |
kind | t.kind() | String |
min/max | t.min(), t.max() | { key, value } | null |
lower/upper bound | t.lowerBound(key), t.upperBound(key) | { key, value } | null |
floor/ceil | t.floor(key), t.ceil(key) | { key, value } | null |
predecessor/successor | t.predecessor(key), t.successor(key) | { key, value } | null |
closest | t.closest(key, opts?) | { key, value, exact } | null |
kClosest | t.kClosest(key, k, opts?) | [{ key, value, exact, distance }] |
rank/select | t.rank(key), t.select(rank) | Int|null, { key, value } | null |
range | t.range(from, to, opts?) | [{ key, value }] |
path | t.path(key) | [{ key, value }] | null |
popMin/popMax | t.popMin(), t.popMax() | { key, value } | null |
bulkLoad | t.bulkLoad(items, opts?) | Tree |
validate | t.validate() | { ok, reason } |
keys/values/items | t.keys(), t.values(), t.items() | Array |
metrics | t.size, t.maxDepth(), t.maxWidth() | Int |
let prices = tree("avl")
let seeds = [18, 22, 27, 35, 44, 56, 63, 71, 89]
seeds.forEach(p ->
prices.set(p, { sku: "p-" + str(p), price: p, })
)
log("floor50:", prices.floor(50))
log("ceil50:", prices.ceil(50))
log("nearest42:", prices.kClosest(42, 3))
log("median:", prices.select(4))
log("rank35:", prices.rank(35))
log("valid:", prices.validate())
7.4 Hierarchical Tree: ntree(rootId, rootValue?)
Explicit parent/children hierarchy for topology navigation.
| Method | Signature | Return |
get/set | t.get(id), t.set(id, value) | node|null, Bool |
append/prepend/insertAt | t.append(parent, child, value), ... | NTree |
remove | t.remove(id, opts?) | Bool |
move | t.move(id, newParent, opts?) | NTree |
parent/children/siblings | t.parent(id), t.children(id), t.siblings(id, opts?) | node|null, [node], [node] |
ancestors/descendants | t.ancestors(id), t.descendants(id, opts?) | [node] |
depth/height | t.depth(id), t.height(id) | Int|null |
lca/pathBetween | t.lca(a, b), t.pathBetween(a, b) | node|null, [node]|null |
subtreeSize | t.subtreeSize(id) | Int|null |
path | t.path(id) | [node]|null |
find/findAll/root | t.find(fn), t.findAll(fn), t.root() | node|null, [node], node |
size | t.size | Int |
let topo = ntree("root", { label: "Root", })
topo.append("root", "api", { label: "API", })
topo.append("root", "worker", { label: "Worker", })
topo.append("api", "http", { label: "HTTP", })
topo.append("worker", "jobs", { label: "Jobs", })
log({
depthJobs: topo.depth("jobs"),
lca: topo.lca("http", "jobs"),
path: topo.pathBetween("http", "jobs").map(n -> n.id),
})
8. Sequence Operators
These are overloaded between arrays and streams (where noted).
| Name | Signature | Return |
filter | filter(array, pred) or filter(pred) | Array / stream stage |
flatMap | flatMap(array, fn) or flatMap(fn) | Array / stream stage |
reduce | reduce(array, fn, init) or reduce(init, fn) | Value / stream sink |
forEach | forEach(array, fn) or forEach(fn) | Unit / stream sink |
sort | sort(array, cmp) or sort()/sort(cmp) | Array / stream stage |
find | find(array, pred) | Value|null |
sum | sum(array) | Int|Float |
take | take(n) | stream stage |
drop | drop(n) | stream stage |
chunk | chunk(size) | stream stage |
window | window(size, step) | stream stage |
throttle | throttle(ms) | stream stage |
debounce | debounce(ms) | stream stage |
distinct | distinct() | stream stage |
count | count() | stream sink Int |
group_count | group_count([keyFn]) | stream sink Map |
reduce_by_key | reduce_by_key(keyFn, init, reducerFn) | stream sink Map |
top | top(n[, scoreFn]) | stream sink Array |
partition | partition(array, pred) or partition(selector[, keys]) | Array pair / branch object |
split | split(pred) (stream) or split(text, sep) (string) | Object / Array<String> |
9. Strings
| Name | Signature | Return |
trim | trim(text) | String |
toLower | toLower(text) | String |
toUpper | toUpper(text) | String |
split | split(text, sep) | Array<String> |
chars | chars(text) | Array<Char> |
contains | contains(text, sub) | Bool |
startsWith | startsWith(text, prefix) | Bool |
endsWith | endsWith(text, suffix) | Bool |
replace | replace(text, old, new) | String |
10. Encoding + Data
| Name | Signature | Return | Notes |
fromJson | fromJson(text) or fromJson() | Value / stream stage | Recoverable parse failures. |
toJson | toJson(value) or toJson() | String / stream stage | Encoding fails on unsupported values. |
fromUtf8 | fromUtf8(bytes) or fromUtf8() | String / stream stage | Recoverable on invalid UTF-8. |
toUtf8 | toUtf8(text) or toUtf8() | Bytes / stream stage | - |
bytesJoin | bytesJoin(arrayOfBytes) | Bytes | Concatenates byte chunks. |
parseInt | parseInt(text) | Int | Runtime error on invalid input. |
11. Time / UUID / Crypto
| Name | Signature | Return |
now | now() | Int (ms epoch) |
timeParseRFC3339 | timeParseRFC3339(text) | Int |
timeFormatRFC3339 | timeFormatRFC3339(ms) | String |
timeAdd | timeAdd(ms, deltaMs) | Int |
timeDiff | timeDiff(aMs, bMs) | Int |
sha256 | sha256(text) | String (hex) |
uuidNew | uuidNew() | String |
uuidParse | uuidParse(text) | String |
uuidValid | uuidValid(text) | Bool |
12. Math + Random
| Name | Signature | Return |
rand | rand() | Int |
randInt | randInt(min, max) | Int |
randFloat | randFloat(min, max) | Float |
abs | abs(number) | Int|Float |
sqrt | sqrt(number) | Float |
pow | pow(base, exp) | Float |
sin | sin(number) | Float |
cos | cos(number) | Float |
tan | tan(number) | Float |
floor | floor(number) | Int |
ceil | ceil(number) | Int |
min | min(a, b) | Int|Float |
max | max(a, b) | Int|Float |
clamp | clamp(v, min, max) | Int|Float |
13. Filesystem
| Name | Signature | Return | Notes |
readFile | readFile(path) | String | Whole-file read as text. |
writeFile | writeFile(path, text) | () | Overwrite. |
appendFile | appendFile(path, text) | () | Append. |
deleteFile | deleteFile(path) | () | - |
exists | exists(path) | Bool | - |
listDir | listDir(path) | Array<String> | - |
reader | reader(path, opts?) | <stream-reader> | Low-level stream handle. |
writer | writer(path, opts?) | <stream-writer> | Low-level stream handle. |
read | read(path, opts?) | <stream-source> | Preferred pipeline source. |
write | write(path, opts?) | <stream-sink> | Preferred pipeline sink. |
14. HTTP
| Name | Signature | Return | Notes |
http | http(url, opts?) | <stream-source> | Preferred HTTP form. |
httpServe | httpServe({ addr, routes }) | Server | Native runtime only. |
httpServerStop | httpServerStop(server) | () | Graceful stop. |
15. SQL
| Name | Signature | Return |
sqlOpen | sqlOpen(dsn) | Db |
sqlClose | sqlClose(db) | () |
sqlExec | sqlExec(connOrTx, query, paramsArray) | { rowsAffected } |
sqlQuery | sqlQuery(connOrTx, query, paramsArray) | Array<Object> |
sqlQueryOne | sqlQueryOne(connOrTx, query, paramsArray) | Object|null |
sqlBegin | sqlBegin(db) | Tx |
sqlCommit | sqlCommit(tx) | () |
sqlRollback | sqlRollback(tx) | () |
16. Signals
| Name | Signature | Return |
signalWatch | signalWatch(["SIGINT", ...]) | Channel<String> |
17. Process API
| Name | Signature | Return | Notes |
proc | proc(spec, opts?) or proc(command, ...args, opts?) | <process> | Starts immediately. |
run | run(spec, opts?) or run(command, ...args, opts?) | RunStatus | Blocking convenience form. |
Process members:
p.pid
p.running
p.stdin // available when stdin: PIPE
p.stdout // available when stdout: PIPE
p.stderr // available when stderr: PIPE
p.abort()
p.kill()
p.signal("SIGTERM")
Status objects:
wait p -> { ok, code, signal, timedOut, aborted, durationMs, }
run(...) -> { ok, code, signal, timedOut, aborted, durationMs, output, error, outputTruncated, errorTruncated, }
18. Stream API
18.1 Sources
read(path, opts?)
stdin(opts?)
http(url, opts?)
fromChannel(ch)
merge(a, b, ...) or merge([a, b, ...])
zip(a, b)
join(left, right, leftKeyFn, rightKeyFn)
18.2 Stages
lines()
fromJson()
toJson()
fromUtf8()
toUtf8()
map(fn)
filter(fn)
flatMap(fn)
distinct()
sort([cmp])
take(n)
drop(n)
chunk(size)
window(size, step)
throttle(ms)
debounce(ms)
tee(sink)
spill(path, opts?)
18.3 Sinks
stdout()
write(path, opts?)
collect()
toChannel(ch)
send(ch)
reduce(init, fn)
forEach(fn)
count()
group_count([keyFn])
reduce_by_key(keyFn, init, reducerFn)
top(n[, scoreFn])
partition(selector[, branchKeys])
split(pred)
exec(specOrCommand...)
18.4 Stream Handle Members
// source or plan
s.read() // [item, eof]
s.close()
// reader
r.read([size]) // [chunk, eof]
r.close()
// writer
w.write(chunk) // bytes written
w.close()
19. Method Sugar
| Type | Properties | Methods |
Array | .length | .map .filter .reduce .forEach .sum .find .sort .push |
String | .length | .split .chars .trim .toLower .toUpper .contains .startsWith .endsWith .replace |
Bytes | .length | - |
Map | - | .get .set .has .delete .keys .values |
Set | .size | .add .has .delete .values |
Tree | .size | .set .get .has .delete .kind .min .max .maxDepth .maxWidth .lowerBound .upperBound .floor .ceil .predecessor .successor .closest .kClosest .rank .select .range .path .popMin .popMax .bulkLoad .validate .keys .values .items |
NTree | .size | .get .set .append .prepend .insertAt .remove .move .parent .children .siblings .ancestors .descendants .depth .height .lca .pathBetween .subtreeSize .path .find .findAll .root |
Channel | - | .send .recv .done |
Task | - | .then .cancel |
Process | .pid .running .stdin .stdout .stderr | .abort .kill .signal |
Stream source/plan | - | .read .close |
Stream reader | - | .read .close |
Stream writer | - | .write .close |
20. Non-Obvious Examples
Overloaded map: constructor, array transform, stream stage
let m = map()
let xs = map([1, 2, 3], x -> x * 2)
let ys = read("items.txt", { type: TEXT, }) | lines() | map(_ + "!") | collect()
partition(selector, keys): branch into named streams
let branches = read("events.ndjson", { type: TEXT, })
| lines()
| filter(_ != "")
| fromJson()
| partition(e -> e.level, ["ERROR", "WARN", "INFO"])
let errors = branches.ERROR | count()
let warns = branches.WARN | count()
log({ errors, warns, })
join(left, right, leftKeyFn, rightKeyFn)
let users = read("users.ndjson", { type: TEXT, }) | lines() | filter(_ != "") | fromJson()
let orders = read("orders.ndjson", { type: TEXT, }) | lines() | filter(_ != "") | fromJson()
let joined = join(users, orders, u -> u.id, o -> o.user_id) | collect()
run vs proc
let st = run("kubectl", "get", "ns") // blocking capture
let p = proc("kubectl", "logs", "-f", "deploy/api", { stdout: PIPE, stderr: NULL, stdoutType: TEXT, })
let [line, eof] = p.stdout.read()
let final = wait p
HTTP stream + JSON stage
let byTeam = http("https://example.com/events.ndjson", { type: TEXT, })
| lines()
| filter(_ != "")
| fromJson()
| group_count(_.team)
exec sink: pipe stream output into external command
let st = read("app.log", { type: TEXT, })
| lines()
| filter(_.contains("ERROR"))
| exec("wc", "-l", { maxOutputBytes: 1024, })
log(st.output.trim())
stream cursor semantics
let s = read("events.log", { type: TEXT, }) | lines()
let [a, eofA] = s.read()
let [b, eofB] = s.read()
s.close()
let [c, eofC] = s.read() // [null, true]
21. Compatibility Notes
- Prefer
http(url, opts?). Legacy blocking http({ method, url, ... }) remains for compatibility but is not the recommended style.
- Some built-ins are overloaded intentionally (
map, split, send). This page lists each valid shape explicitly.