slug.std
slug.std — the Slug standard library
Core utilities available to all Slug programs. Provides type constants, the canonical Error struct, collection transforms, type conversions, string formatting, and common functional helpers.
Type constants
Type symbols returned by type() are available as named constants: NIL_TYPE, BOOLEAN_TYPE, NUMBER_TYPE, STRING_TYPE, LIST_TYPE, MAP_TYPE, BYTES_TYPE, FUNCTION_TYPE, TASK_TYPE, STRUCT_TYPE, SYMBOL_TYPE, ERROR_TYPE.
Use these with pinned patterns for readable type dispatch:
match type(v) {
^STRING_TYPE => ...
^LIST_TYPE => ...
_ => ...
}
Error handling
The canonical error shape is Error{ type, msg, code, data, cause }. Construct errors with Error{ type: "MyError", msg: "something went wrong" } and throw them with throw. There is no try/catch — handle errors via match on return values or defer onerror.
TOC
- BOOLEAN_TYPE
- BYTES_TYPE
- ERROR_TYPE
- FUNCTION_TYPE
- LIST_TYPE
- MAP_TYPE
- NIL_TYPE
- NUMBER_TYPE
- STRING_TYPE
- STRUCT_TYPE
- SYMBOL_TYPE
- TASK_TYPE
- Error
compare(a, b)compute(map, key, f)counter(start)equals(nil)filter(vs, f, acc)find(xs, f)flatMap(vs, f)fmt(str, args)get(map, key)ifNil(nil)isDefined(varName)isStructInstance(v)keys(map)label(symbol)map(vs, f, acc)nonNil(v, f, default)parseNumber(value)put(map, key, value)range(start, end, step, acc)reduce(vs, v, f)remove(map, key)structEquals(m1, m2)swap(list, index1, index2)sym(name)then(m, f)toBoolean(v)toNumber(v)toString(v)type(val)update(list, index, value)zeroIfAbove(a, b)zip(lst1, lst2, acc)zipWith(lst, f)zipWithIndex(lst)
Constants
BOOLEAN_TYPE
sym slug.std#BOOLEAN_TYPE
BYTES_TYPE
sym slug.std#BYTES_TYPE
ERROR_TYPE
sym slug.std#ERROR_TYPE
FUNCTION_TYPE
sym slug.std#FUNCTION_TYPE
LIST_TYPE
sym slug.std#LIST_TYPE
MAP_TYPE
sym slug.std#MAP_TYPE
NIL_TYPE
sym slug.std#NIL_TYPE
Constant for NIL_TYPE, returned by type(nil)
NUMBER_TYPE
sym slug.std#NUMBER_TYPE
STRING_TYPE
sym slug.std#STRING_TYPE
STRUCT_TYPE
sym slug.std#STRUCT_TYPE
SYMBOL_TYPE
sym slug.std#SYMBOL_TYPE
TASK_TYPE
sym slug.std#TASK_TYPE
Structs
Error
struct slug.std#Error{@str type = "Error", @str msg, code = nil, data = nil, cause = nil}
Standard error payload shape for idiomatic error handling.
Always set type to a stable PascalCase string identifying the error kind (e.g. "TypeError", "NotFoundError"). Use cause to chain errors.
| Field | Type | Default | Description |
|---|---|---|---|
type | @str | "Error" | |
msg | @str | — | |
code | nil | ||
data | nil | ||
cause | nil |
Functions
compare(a, b)
fn slug.std#compare(a, b) -> @num
returns -1 if a < b, 1 if a > b, 0 if equal.
Compatible with sort comparator contracts.
| Parameter | Type | Default |
|---|---|---|
a | — | |
b | — |
compute(map, key, f)
fn slug.std#compute(@map map, key, f) -> @map
applies f(key, currentValue) to the value at key and returns the updated map.
If key is absent, currentValue is nil.
| Parameter | Type | Default |
|---|---|---|
map | @map | — |
key | — | |
f | — |
Examples
compute({:k: 1}, :k, function group: [{|| 2 2 false} => fn((k), (v)) {
{(v + 1)}
}]) // => {:k: 2}
compute({}, :k, function group: [{|| 2 2 false} => fn((k), (v)) {
{(v == nil)}
}]) // => {:k: true}
counter(start)
fn slug.std#counter(@num start = 0) -> @fn
returns a function that increments and returns a counter on each call.
The counter starts at start. Each call returns the next value.
val c = counter(0)
c() // => 0
c() // => 1
c() // => 2
| Parameter | Type | Default |
|---|---|---|
start | @num | 0 |
equals(nil)
fn slug.std#equals(nil) -> @bool
deep equality for maps, recursively comparing values for all keys. nil
Examples
equals(nil, nil) // => false
equals({}, nil) // => false
equals(nil, {}) // => false
equals({}, {}) // => true
equals({:k1: 1}, {:k1: 1}) // => true
equals({:k1: 1}, {}) // => false
equals({:k1: 1}, {:k2: 2}) // => false
filter(vs, f, acc)
fn slug.std#filter(@list vs, @fn f, @list acc = []) -> @list
returns a new list containing only elements for which f returns true.
| Parameter | Type | Default |
|---|---|---|
vs | @list | — |
f | @fn | — |
acc | @list | [] |
Examples
filter([1, 2, 3, 4], function group: [{| 1 1 false} => fn((v)) {
{((v % 2) == 0)}
}]) // => [2, 4]
find(xs, f)
fn slug.std#find(@list xs, @fn f) -> ?
returns the first element of xs for which f returns true, or nil.
| Parameter | Type | Default |
|---|---|---|
xs | @list | — |
f | @fn | — |
flatMap(vs, f)
fn slug.std#flatMap(@list vs, @fn f) -> @list
applies f to each element of vs and concatenates the resulting lists.
f must return a list or a single value (which is treated as a one-element list).
| Parameter | Type | Default |
|---|---|---|
vs | @list | — |
f | @fn | — |
Examples
flatMap([1, 2, 3], function group: [{| 1 1 false} => fn((n)) {
{[n, n]}
}]) // => [1, 1, 2, 2, 3, 3]
flatMap([1, 2, 3], function group: [{| 1 1 false} => fn((n)) {
{if((n % 2) == 0) {[n]} else {[]}}
}]) // => [2]
fmt(str, args)
fn slug.std#fmt(@str str, ...args) -> @str
formats a string using {} placeholders and optional format specifiers.
Placeholders:
-
{}— next positional argument -
{0},{1}— explicit argument index -
{:.2f}— float with 2 decimal places -
{:d}— integer (truncates decimals) -
{:,}— number with thousands separators -
{:.1%}— percentage with 1 decimal place -
{:>8}— right-align in width 8 -
{:<10s}— left-align string in width 10 -
{:^10s}— centre string in width 10 -
\{and\}— literal braces
| Parameter | Type | Default |
|---|---|---|
str | @str | — |
args | — |
Examples
fmt("Hello {}", "Slug") // => "Hello Slug"
fmt("{1} then {0}", "A", "B") // => "B then A"
fmt("x={:.2f} y={:.2f}", 1.2, 3.4) // => "x=1.20 y=3.40"
fmt("{:d}", 12.5) // => "12"
fmt("{:,}", 1234567) // => "1,234,567"
fmt("{:.1%}", 0.1234) // => "12.3%"
fmt("value=\{x\}") // => "value={x}"
fmt("|{:>8}|", 12.3) // => "| 12.3|"
fmt("|{:<10s}|", "Slug") // => "|Slug |"
fmt("|{:^10s}|", "Slug") // => "| Slug |"
get(map, key)
fn slug.std#get(@map map, key) -> ?
returns the value for key in map, or nil if absent.
| Parameter | Type | Default |
|---|---|---|
map | @map | — |
key | — |
Examples
get({}, :k) // => nil
get({:k: 1}, :k) // => 1
ifNil(nil)
fn slug.std#ifNil(nil) -> ?
returns default if v is nil; returns v otherwise. nil
isDefined(varName)
fn slug.std#isDefined(@str varName) -> @bool
returns true if varName is defined as a binding in the current scope.
| Parameter | Type | Default |
|---|---|---|
varName | @str | — |
Examples
isDefined("type") // => true
isDefined("__not_defined__") // => false
isStructInstance(v)
fn slug.std#isStructInstance(v) -> @bool
returns true if v is an instance of a struct (not a struct schema).
| Parameter | Type | Default |
|---|---|---|
v | — |
keys(map)
fn slug.std#keys(map) -> @list
returns a list of all keys in a map.
Key order is not guaranteed. For sorted keys use slug.list#sort.
| Parameter | Type | Default |
|---|---|---|
map | — |
Examples
keys({}) // => []
keys({:k: 1}) // => [:k]
label(symbol)
fn slug.std#label(symbol) -> @str
returns the string label of a symbol.
| Parameter | Type | Default |
|---|---|---|
symbol | — |
Examples
label(:foo) // => "foo"
label(:"a b") // => "a b"
map(vs, f, acc)
fn slug.std#map(@list vs, @fn f, acc = []) -> @list
applies f to each element of vs and returns the resulting list.
| Parameter | Type | Default |
|---|---|---|
vs | @list | — |
f | @fn | — |
acc | [] |
Examples
map([1, 2], function group: [{| 1 1 false} => fn((n)) {
{(n * 2)}
}]) // => [2, 4]
nonNil(v, f, default)
fn slug.std#nonNil(v, @fn f, default = nil) -> ?
returns default if v is nil; calls f(v) and returns the result otherwise.
| Parameter | Type | Default |
|---|---|---|
v | — | |
f | @fn | — |
default | nil |
parseNumber(value)
fn slug.std#parseNumber(@str value) -> @num
parses a numeric string to a number. Throws on invalid input.
| Parameter | Type | Default |
|---|---|---|
value | @str | — |
Examples
parseNumber("1") // => 1
parseNumber("1.1") // => 1.1
put(map, key, value)
fn slug.std#put(@map map, key, value) -> @map
returns a new map with key set to value.
| Parameter | Type | Default |
|---|---|---|
map | @map | — |
key | — | |
value | — |
Examples
put({}, :k, "v") // => {:k: v}
range(start, end, step, acc)
fn slug.std#range(@num start, @num end, @num step = 1, @list acc = []) -> @list
generates a list of numbers from start (inclusive) to end (exclusive) by step.
Returns an empty list if the range direction contradicts the step sign.
| Parameter | Type | Default |
|---|---|---|
start | @num | — |
end | @num | — |
step | @num | 1 |
acc | @list | [] |
Examples
range(0, 0) // => []
range(0, 2) // => [0, 1]
range(0, 6, 2) // => [0, 2, 4]
range(0, 6, -2) // => []
range(6, 0, -2) // => [6, 4, 2]
reduce(vs, v, f)
fn slug.std#reduce(@list vs, v, @fn f) -> ?
folds vs left with f, starting from initial value v.
| Parameter | Type | Default |
|---|---|---|
vs | @list | — |
v | — | |
f | @fn | — |
Examples
reduce([], 0, function group: [{|| 2 2 false} => fn((a), (b)) {
{(a + b)}
}]) // => 0
reduce([1, 2, 3], 0, function group: [{|| 2 2 false} => fn((a), (b)) {
{(a + b)}
}]) // => 6
reduce([1, 2, 3], 9, function group: [{|| 2 2 false} => fn((a), (b)) {
{(a + b)}
}]) // => 15
remove(map, key)
fn slug.std#remove(@map map, key) -> @map
returns a new map with key removed. No-op if key is absent.
| Parameter | Type | Default |
|---|---|---|
map | @map | — |
key | — |
Examples
remove({}, :k) // => {}
remove({:k: 1}, :k) // => {}
remove({:k: 1}, :j) // => {:k: 1}
structEquals(m1, m2)
fn slug.std#structEquals(m1, m2) -> @bool
deep equality for struct types and struct instances.
Returns false if either value is nil, if their types differ, or if neither is a struct instance or struct schema.
| Parameter | Type | Default |
|---|---|---|
m1 | — | |
m2 | — |
swap(list, index1, index2)
fn slug.std#swap(@list list, @num index1, @num index2) -> @list
returns a new list with elements at index1 and index2 swapped.
| Parameter | Type | Default |
|---|---|---|
list | @list | — |
index1 | @num | — |
index2 | @num | — |
Examples
swap([1, 2], 0, 1) // => [2, 1]
sym(name)
fn slug.std#sym(@str name) -> @sym
converts a string to a symbol.
| Parameter | Type | Default |
|---|---|---|
name | @str | — |
Examples
sym("foo") // => :foo
sym("foo bar") // => :"foo bar"
sym("Content-Type") // => :"Content-Type"
then(m, f)
fn slug.std#then(m, @fn f) -> ?
applies f to m and returns the result. Useful for call-chain threading.
m /> then(fn(v) { ... }) is equivalent to (fn(v) { ... })(m).
| Parameter | Type | Default |
|---|---|---|
m | — | |
f | @fn | — |
Examples
then(1, function group: [{| 1 1 false} => fn((v)) {
{(v * 2)}
}]) // => 2
then({:n: Slug}, function group: [{| 1 1 false} => fn((v)) {
{(v[:n])}
}]) // => "Slug"
toBoolean(v)
fn slug.std#toBoolean(v) -> @bool
converts a value to @bool.
Numeric 1 → true, 0 → false. Strings "true", "yes", "1", "TRUE", "YES" → true; "false", "no", "0", "FALSE", "NO" → false. Other string values throw TypeError.
| Parameter | Type | Default |
|---|---|---|
v | — |
Throws: @struct(Error{type:TypeError})
Examples
toBoolean(nil) // => false
toBoolean(0) // => false
toBoolean(1) // => true
toBoolean(true) // => true
toBoolean(false) // => false
toBoolean("true") // => true
toBoolean("yes") // => true
toBoolean("1") // => true
toBoolean("false") // => false
toBoolean("no") // => false
toBoolean("0") // => false
toNumber(v)
fn slug.std#toNumber(v) -> @num
converts a value to @num.
Passes through numbers, parses numeric strings, returns nil for nil. Throws TypeError for other types.
| Parameter | Type | Default |
|---|---|---|
v | — |
Throws: @struct(Error{type:TypeError})
Examples
toNumber(nil) // => nil
toNumber(1) // => 1
toNumber(1.1) // => 1.1
toNumber("1") // => 1
toNumber("1.1") // => 1.1
toString(v)
fn slug.std#toString(v) -> @str
converts a value to a string representation.
Returns nil for nil, passes through strings, and uses string concatenation (v + "") for all other types.
| Parameter | Type | Default |
|---|---|---|
v | — |
Examples
toString(nil) // => nil
toString("str") // => "str"
toString(1.1) // => "1.1"
toString(true) // => "true"
type(val)
fn slug.std#type(val) -> @sym
returns a symbol indicating the runtime type of val.
Result is one of the *_TYPE constants exported by this module.
| Parameter | Type | Default |
|---|---|---|
val | — |
Examples
type(nil) // => :nil
type(true) // => :bool
type(1) // => :number
type(1.1) // => :number
type("Hello Slug!") // => :string
type([1, 2]) // => :list
type({:key: value}) // => :map
type(0x"ff") // => :bytes
type(function group: [{| 1 1 false} => fn((a)) {
{a}
}]) // => :function
update(list, index, value)
fn slug.std#update(@list list, @num index, value) -> @list
returns a new list with the element at index replaced by value.
| Parameter | Type | Default |
|---|---|---|
list | @list | — |
index | @num | — |
value | — |
Examples
update([1, 2, 3], 1, 99) // => [1, 99, 3]
zeroIfAbove(a, b)
fn slug.std#zeroIfAbove(@num a, @num b) -> @num
returns a if a < b, otherwise returns 0.
| Parameter | Type | Default |
|---|---|---|
a | @num | — |
b | @num | — |
Examples
zeroIfAbove(1, 1) // => 0
zeroIfAbove(1, 2) // => 1
zeroIfAbove(2, 1) // => 0
zip(lst1, lst2, acc)
fn slug.std#zip(@list lst1, @list lst2, acc = []) -> @list
zips two lists into a list of [a, b] pairs.
Stops at the shorter list. Extra elements from the longer list are discarded.
| Parameter | Type | Default |
|---|---|---|
lst1 | @list | — |
lst2 | @list | — |
acc | [] |
Examples
zip([], []) // => []
zip([1], []) // => []
zip([], [1]) // => []
zip([1], [2]) // => [[1, 2]]
zipWith(lst, f)
fn slug.std#zipWith(@list lst, f) -> @list
zips a list with the results of calling f for each element.
Returns a list of [element, f()] pairs. f is called once per element.
| Parameter | Type | Default |
|---|---|---|
lst | @list | — |
f | — |
Examples
zipWith(["a", "b"], function group: [{ 0 0 false} => fn() {
{1}
}]) // => [["a", 1], ["b", 1]]
zipWithIndex(lst)
fn slug.std#zipWithIndex(@list lst) -> @list
zips a list with its zero-based indices.
Returns a list of [element, index] pairs.
| Parameter | Type | Default |
|---|---|---|
lst | @list | — |
Examples
zipWithIndex([]) // => []
zipWithIndex(["a", "b"]) // => [["a", 0], ["b", 1]]