libstd is the core standard library for Oak, providing essential functions for working with Oak values, iterators, and control flow. It defines the fundamental building blocks for functional programming patterns in Oak.
std := import('std')
// or destructure specific functions
{ map: map, filter: filter, reduce: reduce } := import('std')
Returns its first argument unchanged.
identity(5) // => 5
identity('hello') // => 'hello'
Returns a predicate function that checks if its argument equals x.
isThree := is(3)
isThree(3) // => true
isThree(5) // => false
Returns a function that always returns x, regardless of arguments.
alwaysFive := constantly(5)
alwaysFive() // => 5
alwaysFive(1, 2, 3) // => 5
Returns x if x is not null, otherwise returns base. Useful for optional function arguments with default values.
fn greet(name) {
name := default(name, 'World')
'Hello, ' + name
}
greet('Alice') // => 'Hello, Alice'
greet() // => 'Hello, World'
Converts a number to its hexadecimal string representation. Fails for negative values.
toHex(255) // => 'ff'
toHex(16) // => '10'
Parses a hexadecimal string to an integer. Returns ? if input is invalid.
fromHex('ff') // => 255
fromHex('10') // => 16
fromHex('invalid') // => ?
Constrains two values n and m to the range [min, max], ensuring n <= m.
clamp(0, 10, 5, 8) // => [5, 8]
clamp(0, 10, -5, 15) // => [0, 10]
Returns a copy of a substring or sublist from index min (inclusive) to max (exclusive). Both min and max are optional (default to 0 and len(xs)).
slice([1, 2, 3, 4, 5], 1, 4) // => [2, 3, 4]
slice('hello', 1, 4) // => 'ell'
slice([1, 2, 3], 1) // => [2, 3]
Creates a shallow copy of any Oak value.
original := [1, 2, 3]
copy := clone(original)
copy << 4 // original remains [1, 2, 3]
Returns a list of numbers from start to end (exclusive), incrementing by step. Defaults: step = 1, start = 0.
range(5) // => [0, 1, 2, 3, 4]
range(2, 5) // => [2, 3, 4]
range(0, 10, 2) // => [0, 2, 4, 6, 8]
range(10, 0, -2) // => [10, 8, 6, 4, 2]
Reverses the order of elements in an iterable, producing a copy.
reverse([1, 2, 3]) // => [3, 2, 1]
reverse('hello') // => 'olleh'
Transforms each element of xs using function f. The function receives (element, index).
map([1, 2, 3], fn(x) x * 2) // => [2, 4, 6]
map(['a', 'b'], fn(x, i) x + string(i)) // => ['a0', 'b1']
// If f is a string/atom/int, it acts as a property accessor
map([{a: 1}, {a: 2}], 'a') // => [1, 2]
Calls function f for each element. The function receives (element, index). Returns ?.
each([1, 2, 3], fn(x) println(x))
// Prints: 1, 2, 3
Returns only elements where predicate f returns true. Function receives (element, index).
filter([1, 2, 3, 4], fn(x) x % 2 = 0) // => [2, 4]
filter([{age: 20}, {age: 30}], fn(p) p.age > 25) // => [{age: 30}]
Returns only elements where predicate f returns false. Opposite of filter.
exclude([1, 2, 3, 4], fn(x) x % 2 = 0) // => [1, 3]
Divides xs into two lists [is, isnt] based on predicate f.
separate([1, 2, 3, 4], fn(x) x % 2 = 0)
// => [[2, 4], [1, 3]]
Accumulates elements starting with seed. The reducer receives (accumulator, element, index).
reduce([1, 2, 3], 0, fn(acc, x) acc + x) // => 6
reduce(['a', 'b', 'c'], '', fn(acc, x) acc + x) // => 'abc'
Flattens a list of lists by one level.
flatten([[1, 2], [3, 4], [5]]) // => [1, 2, 3, 4, 5]
Removes all null (?) elements from a list.
compact([1, ?, 2, ?, 3]) // => [1, 2, 3]
Returns true if at least one element satisfies the predicate (or is truthy if no predicate given).
some([false, true, false]) // => true
some([1, 2, 3], fn(x) x > 2) // => true
some([1, 2, 3], fn(x) x > 5) // => false
Returns true if all elements satisfy the predicate (or are truthy if no predicate given).
every([true, true, true]) // => true
every([1, 2, 3], fn(x) x > 0) // => true
every([1, 2, 3], fn(x) x > 2) // => false
Joins two iterables together, mutating the first argument.
a := [1, 2]
append(a, [3, 4]) // => [1, 2, 3, 4]
// a is now [1, 2, 3, 4]
Joins two iterables without mutating either value.
a := [1, 2]
b := join(a, [3, 4]) // => [1, 2, 3, 4]
// a remains [1, 2]
Pairs up elements from two iterables. Default zipper creates 2-element lists.
zip([1, 2, 3], [4, 5, 6]) // => [[1, 4], [2, 5], [3, 6]]
zip([1, 2, 3], [4, 5, 6], fn(a, b) a * b) // => [4, 10, 18]
Divides xs into partitions. If by is an integer, partitions have that size. If by is a function, partitions change when the function result changes.
partition([1, 2, 3, 4, 5, 6], 2) // => [[1, 2], [3, 4], [5, 6]]
partition([1, 1, 2, 2, 3], fn(x) x) // => [[1, 1], [2, 2], [3]]
Removes consecutive duplicate elements. For global uniqueness, sort first.
uniq([1, 1, 2, 3, 3, 3, 4]) // => [1, 2, 3, 4]
uniq([1, 2, 1], fn(x) x) // => [1, 2, 1] (not consecutive)
Returns the first element of an iterable.
first([1, 2, 3]) // => 1
first('hello') // => 'h'
Returns the last element of an iterable.
last([1, 2, 3]) // => 3
last('hello') // => 'o'
Returns the first n elements.
take([1, 2, 3, 4, 5], 3) // => [1, 2, 3]
take('hello', 2) // => 'he'
Returns the last n elements.
takeLast([1, 2, 3, 4, 5], 3) // => [3, 4, 5]
takeLast('hello', 2) // => 'lo'
Returns the index of the first element matching the predicate, or -1 if not found.
find([10, 20, 30], fn(x) x > 15) // => 1
find([1, 2, 3], fn(x) x > 10) // => -1
Returns the index of the last element matching the predicate (searching backwards), or -1.
rfind([10, 20, 30, 20], fn(x) x = 20) // => 3
Returns the index of the first element equal to x, or -1.
indexOf([1, 2, 3, 2], 2) // => 1
indexOf([1, 2, 3], 5) // => -1
Returns the index of the last element equal to x (searching backwards), or -1.
rindexOf([1, 2, 3, 2], 2) // => 3
Returns true if the iterable contains an element equal to x.
contains?([1, 2, 3], 2) // => true
contains?([1, 2, 3], 5) // => false
Returns a list of all values in an object (order arbitrary).
values({a: 1, b: 2, c: 3}) // => [1, 2, 3] (order may vary)
Returns a list of [key, value] pairs (order arbitrary).
entries({a: 1, b: 2}) // => [['a', 1], ['b', 2]] (order may vary)
Constructs an object from a list of [key, value] pairs.
fromEntries([['a', 1], ['b', 2]]) // => {a: 1, b: 2}
Merges multiple objects onto the first object, mutating it. Returns ? if no objects given.
a := {x: 1}
merge(a, {y: 2}, {z: 3}) // => {x: 1, y: 2, z: 3}
// a is now {x: 1, y: 2, z: 3}
Returns a wrapper function that ensures f is called exactly once, no matter how many times the wrapper is called.
init := once(fn() println('Initialized!'))
init() // Prints: Initialized!
init() // Does nothing
init() // Does nothing
- Many functions accept a
predparameter that can be:- A function receiving
(element, index) - A string/atom/int to access a property of each element
- A function receiving
- Predicates are converted internally using
_asPredicate() - Most functions return copies rather than mutating the original, except
append()andmerge()