Builtin Functions
The language trys to follow Python's batteries included motto, where-by all desired functionality is included out of the box. This is achieved by the inclusion of many different builtin functions, allowing you tackle many general-purpose and Advent of Code specific problems. The following builtin functions are available in all runtimes:
Collection
list
list(value)
Return the List representation of the given value.
list([1, 2, 3])
list({1, 2, 3})
Ouput is a List of List tuples [key, value]
.
list(#{1: 2, 3: 4})
list("ab")
list(1..5)
list(1..=5)
set
set(value)
Return the Set representation of the given value.
set([1, 2, 3])
set({1, 2, 3})
set("ab")
set(1..5)
set(1..=5)
dict
dict(value)
Return the Dictionary representation of the given value.
Input is a List of List tuples [key, value]
.
dict([[1, 2], [3, 4]])
dict(#{1: 2, 3: 4})
get
get(index, collection)
Get an element within a collection following the indexing rules.
If an element can not be found at that index then nil
is returned.
get(1, [1, 2])
get(1, {1, 2})
get(1, #{1: 2, 3: 4})
get(1, "ab")
get(1, 1..5)
get(1, 1..=5)
get(1, 0..)
size
size(collection)
Get the size of a collection.
size([1, 2])
size({1, 2})
size(#{1: 2, 3: 4})
size("ab")
size(1..5)
size(1..=5)
push
push(value, collection)
Add a new value to a collection.
The value is appended to the end of the List.
push(3, [1, 2])
push(3, {1, 2})
assoc
assoc(key, value, collection)
Associate the provided key/index with the given value in a collection.
assoc(0, 3, [1, 2])
If the index is not already present nil
values are inserted up to the given index.
assoc(1, 1, [])
assoc(1, 1, #{1: 2, 3: 4})
assoc(0, 1, #{1: 2, 3: 4})
update
update(key, updater, collection)
Update the given index/key of a collection using the supplied pure updater
function.
The updater
function is supplied the current value at the given index/key, if not present nil
is supplied.
update(0, _ + 1, [1, 2])
If the index is not already present nil
values are inserted up to the given index.
update(1, || 1, [])
update(0, || 1, #{})
update(1, _ + 1, #{1: 2, 3: 4})
update_d
update_d(key, default, updater, collection)
Update the given index/key of a collection using the supplied pure updater
function.
The updater
function is supplied the current value at the given index/key, if not present the default value is supplied.
update_d(0, 0, _ + 1, [1, 2])
If the index is not already present nil
values are inserted up to the given index.
update_d(1, 0, _ + 1, [])
update_d(0, 0, _ + 1, #{})
update_d(1, 0, _ + 1, #{1: 2, 3: 4})
map
map(mapper, collection)
Return a collection with a pure mapper
function applied over each element within the given collection.
map(_ + 1, [1, 2])
map(_ + 1, {1, 2})
map(_ + 1, #{1: 2, 3: 4})
The mapper
function is suppled both the value and key in the context of a Dictionary.
map(|_, k| k + 1, #{1: 2, 3: 4})
Each character is considered an element within the mapping. The returned collection is a List.
map(_ * 2, "ab")
Lazy Sequences return another Lazy Sequence, which when resolved will lazily apply the required mapping.
map(_ + 1, 1..5) |> list
map(_ + 1, 1..=5) |> list
map(_ + 1, 0..) |> take(3)
map(_ + 1, repeat(1)) |> take(3)
filter
filter(predicate, collection)
Return a collection based on a pure predicate
function holding truthy for the given element in a collection.
filter(_ == 1, [1, 2])
filter(_ == 1, {1, 2})
filter(_ == 2, #{1: 2, 3: 4})
The predicate
function is suppled both the value and key in the context of a Dictionary.
filter(|_, k| k == 3, #{1: 2, 3: 4})
Each character is considered an element within the predicate. The returned collection is a List.
filter(_ == "a", "ab")
Lazy Sequences return another Lazy Sequence, which when resolved will lazily apply the required filter.
filter(_ % 2, 1..5) |> list
filter(_ % 2, 1..=5) |> list
filter(_ % 2, 0..) |> take(3)
filter(_ != 2, cycle([1, 2, 3])) |> take(3)
each
each(side_effect, collection)
Apply a side-effecting function over each element in the given collection.
let mut acc = 0;
each(|v| acc = acc + v, [1, 2]);
acc;
let mut acc = 0;
each(|v| acc = acc + v, {1, 2});
acc;
let mut acc = 0;
each(|v| acc = acc + v, #{1: 2, 3: 4});
acc;
The predicate
function is suppled both the value and key in the context of a Dictionary.
let mut acc = 0;
each(|_, k| acc = ac + k, #{1: 2, 3: 4});
acc;
Each character is considered an element within the iteration. The returned collection is a List.
let mut acc = 0;
each(|_| acc = acc + 1, "ab");
acc;
The function can break
which will terminate the collection iteration early.
let mut acc = 0;
each(|v| acc = acc + v, 1..5);
acc;
let mut acc = 0;
each(|v| acc = acc + v, 1..=5);
acc;
let mut acc = 0;
0.. |> each |v| {
if v == 10 { break nil } else { acc = acc + v }
};
acc;
let mut acc = 0;
iterate(_ + 1, 1) |> each |v| {
if v == 10 { break nil } else { acc = acc + v }
};
acc;
reduce
reduce(reducer, collection)
Apply a pure reducer
function over a given collection.
The initial accumulator value supplied upon first iteration is the first element in the collection.
If the collection is empty then an error is thrown.
reduce(+, [1, 2])
reduce(+, {1, 2})
reduce(+, #{1: 2, 3: 4})
The reducer
function is suppled both the value and key in the context of a Dictionary.
reduce(|acc, _, k| acc + k, #{1: 2, 3: 4})
Each character is considered an element within the reduction. The returned collection is a List.
reduce(|acc, ch| ch + acc, "ab")
The function can break
which will terminate the collection iteration early.
reduce(+, 1..5)
reduce(+, 1..=5)
0.. |> reduce |acc, v| {
if v == 10 { break acc } else { acc + v }
}
iterate(_ + 1, 1) |> reduce |acc, v| {
if v == 10 { break acc } else { acc + v }
}
fold
fold(initial, folder, collection)
Apply a pure folder
function over a given collection.
The initial fold receives the first element and the initial value supplied.
If the collection is empty then the initial value is returned.
fold(0, +, [1, 2])
fold(0, +, {1, 2})
fold(0, +, #{1: 2, 3: 4})
The folder
function is suppled both the value and key in the context of a Dictionary.
fold(0, |acc, _, k| acc + k, #{1: 2, 3: 4})
Each character is considered an element within the fold. The returned collection is a List.
fold(0, _ + 1, "ab")
The function can break
which will terminate the collection iteration early.
fold(0, +, 1..5)
fold(0, +, 1..=5)
0.. |> fold (0) |acc, v| {
if v == 10 { break acc } else { acc + v }
}
iterate(_ + 1, 1) |> fold (0) |acc, v| {
if v == 10 { break acc } else { acc + v }
}
fold_s
fold_s(initial, folder, collection)
Apply a pure folder
function over a given collection, with optional state which is passed along throughout the fold.
The accumulated value is a List comprising of the first element being the resulting folded value, and other elements being state you wish to pass on to the next iteration.
Upon completion, the extra state is discarded and the folded value is returned.
If the collection is empty then the initial value is returned.
50..100 |> fold_s(
[0, 0, 0],
|[acc, x, y], val| [acc + x * y * val, val, val / 2]
)
find
find(predicate, collection)
Apply a pure predicate
function over a given collection, returning the first element where the predicate holds truthy.
find(_ % 2, [1, 2])
find(_ % 2, {1, 2})
find(_ % 2, #{1: 2, 3: 4})
The predicate
function is suppled both the value and key in the context of a Dictionary.
find(|_, k| k % 2, #{1: 2, 3: 4})
Each character is considered an element within the predicate. The returned collection is a List.
find(_ == "b", "ab")
find(_ % 2, 1..5)
find(_ % 2, 1..=5)
find(_ % 2, 0..)
find(_ % 2, iterate(_ + 1, 1))
scan
scan(initial, folder, collection)
Return a collection which includes the result of each iteration of folding a pure folder
function over each element within the given collection.
scan(0, +, [1, 2])
scan(0, +, {1, 2})
scan(0, +, #{1: 2, 3: 4})
The folder
function is suppled both the value and key in the context of a Dictionary.
scan(0, |acc, _, k| acc + k, #{1: 2, 3: 4})
Each character is considered an element within the fold. The returned collection is a List.
scan("", +, "ab")
scan(0, +, 1..5)
scan(0, +, 1..=5)
flat_map
flat_map(mapper, collection)
Apply a pure mapper
function over a given collection with the resulting mapped List results being flattened into a single List.
flat_map(_ * 2, [[1, 2], [3, 4]])
filter_map
filter_map(mapper, collection)
Apply a pure mapper
function over a given collection and filter out the mapped values based on them being truthy.
This is a convenience function (inspired by Rust) for the common place map(..) |> filter(..)
pattern.
[1, 2, 3, 4] |> filter_map(|v| if v % 2 { v * 2 })
{1, 2, 3, 4} |> filter_map(|v| if v % 2 { v * 2 })
#{1: 2, 3: 4} |> filter_map(|v| if v != 2 { v * 2 })
The mapper
function is suppled both the value and key in the context of a Dictionary.
#{1: 2, 3: 4} |> filter_map(|_, k| if k != 1 { k * 2 })
Each character is considered an element within the mapping. The returned collection is a List.
"ab" |> filter_map(|v| if v != "a" { v * 2 })
1..5
|> filter_map(|v| if v % 2 { v * 2 })
|> list
1..=5
|> filter_map(|v| if v % 2 { v * 2 })
|> list
1..
|> filter_map(|v| if v % 2 { v * 2 })
|> take(3)
iterate(_ + 1, 1)
|> filter_map(|v| if v % 2 { v * 2 })
|> take(3)
find_map
find_map(mapper, collection)
Apply a pure mapper
function over a given collection and find the first mapped element where the value returned is truthy.
This is a convenience function (inspired by Rust) for the common place map(..) |> find(..)
pattern.
[1, 2] |> find_map(|v| if v % 2 { v * 2 })
{1, 2} |> find_map(|v| if v % 2 { v * 2 })
#{1: 2, 3: 4} |> find_map(|v| if v != 2 { v * 2 })
The mapper
function is suppled both the value and key in the context of a Dictionary.
#{1: 2, 3: 4} |> find_map(|_, k| if k != 1 { k * 2 })
Each character is considered an element within the mapping. The returned collection is a List.
"ab" |> find_map(|v| if v != "a" { v * 2 })
1..5 |> find_map(|v| if v % 2 { v * 2 })
1..=5 |> find_map(|v| if v % 2 { v * 2 })
1.. |> find_map(|v| if v % 2 { v * 2 })
iterate(_ + 1, 1)
|> find_map(|v| if v % 2 { v * 2 })
count
count(predicate, collection)
Count the total number of elements where the pure predicate
function holds truthy.
count(_ % 2, [1, 2, 3, 4])
count(_ % 2, {1, 2, 3, 4})
count(_ % 2, #{1: 2, 3: 4})
The predicate
function is suppled both the value and key in the context of a Dictionary.
count(|_, k| k % 2, #{1: 2, 3: 4})
Each character is considered an element within the predicate. The returned collection is a List.
count(_ == "a", "ab")
count(_ % 2, 1..5)
count(_ % 2, 1..=5)
zip
zip(collection, ..collections)
Takes any number of iterables as an argument and aggregates them together producing a List/Lazy Sequence of List tuples. Each List tuple contains elements of all iterables occurring at the same position, stopping when the shortest iterables is exhausted.
zip(0.., "abc", [1.5, 2.5, 3.5])
zip(0.., "abcdef", [1.5, 2.5, 3.5])
If any of the iterables have a finite size then a List is returned, else a Lazy Sequence is produced.
zip(0.., 1..) |> take(3)
sum
sum(collection)
Sum all the Integer elements within a collection.
sum([1, 2])
sum({1, 2})
sum(#{1: 2, 3: 4})
sum(1..5)
sum(1..=5)
max
max(..values)
Find the largest (maximum) element within a collection. The collections can be supplied as a single argument List (containing multiple collections), or as a multi-arity function call.
max(1, 2) == max([1, 2])
max([1, 2])
max({1, 2})
max(#{1: 2, 3: 4})
max(1..5)
max(1..=5)
min
min(..values)
Find the smallest (minimum) element within a collection. The collections can be supplied as a single argument List (containing multiple collections), or as a multi-arity function call.
min(1, 2) == min([1, 2])
min([1, 2])
min({1, 2})
min(#{1: 2, 3: 4})
min(1..5)
min(1..=5)
skip
skip(total, collection)
Skip a number of elements within a collection. If the collection is a Lazy Sequence the skip is applied when the collection is lazily resolved.
skip(1, [1, 2, 3])
skip(1, {1, 2, 3})
skip(2, 1..5)
skip(2, 1..=5)
skip(2, 1..) |> take(3)
skip(2, iterate(_ + 1, 1)) |> take(3)
take
take(total, collection)
Take a number of elements from a collection.
If the collection is a Lazy Sequence then the collection is resolved with any outstanding operations (map
, skip
etc.) being applied.
take(2, [1, 2, 3])
take(2, {1, 2, 3})
take(2, 1..5)
take(2, 1..=5)
take(2, 1..)
take(2, iterate(_ + 1, 1))
sort
sort(comparator, collection)
Sort the collection based on a supplied pure comparator
function.
The comparator function accepts two values (a, b) from the collection and can either return:
An Boolean value, with false
signifying a < b and true
signifying a > b.
sort(>, [3, 2, 1])
An Integer value, with a negative value signifying a < b, zero signifying a == b, and a positive value signifying a > b.
sort(-, [3, 2, 1])
reverse
reverse(collection)
Reverse the order of a given List collection.
reverse([1, 2, 3])
reverse("abc")
reverse(1..5)
reverse(1..=5)
repeat
repeat(value)
Generate a Lazy Sequence which repeats the provided value indefinitely.
repeat(1) |> take(3)
cycle
cycle(list)
Generate a Lazy Sequence which cycles through each element in a List indefinitely, looping back to the start once exhausted.
cycle([1, 2, 3]) |> take(4)
Each character is considered an element within the Lazy Sequence.
cycle("abc") |> take(4)
iterate
iterate(generator, initial)
Generate a Lazy Sequence which supplies a provided pure generator
function with the previous result (starting with an initial value) to produce the next value in the sequence.
iterate(|[a, b]| [b, a + b], [0, 1])
|> skip(9)
|> take(1)
iterate(_ * 2, 1) |> take(5)
keys
keys(dictionary)
Return the keys in a given Dictionary as a List.
keys(#{1: 2, 3: 4})
values
values(dictionary)
Return the values in a given Dictionary as a List.
values(#{1: 2, 3: 4})
first
first(collection)
Return the first element within the collection (aka head).
If the collection is empty then nil
is returned.
first([1, 2])
first({1, 2})
Each character is considered an element.
first("ab")
first(1..5)
first(1..=5)
first(1..)
first(iterate(_ + 1, 1))
second
second(collection)
Return the second element within the collection.
If the collection does not contain a second element then nil
is returned.
second([1, 2])
second({1, 2})
Each character is considered an element.
second("ab")
second(1..5)
second(1..=5)
second(1..)
second(iterate(_ + 1, 1))
rest
rest(collection)
Return the collection with the first element omitted (aka tail). If the collection does not have more than one element then an empty List is returned.
rest([1, 2])
rest({1, 2})
Each character is considered an element.
rest("ab")
rest(1..5)
rest(1..=5)
rest(1..)
rest(iterate(_ + 1, 1))
union
union(..values)
Return the elements (as a Set) which are found in any of the provided collections. The collections can be supplied as a single argument List (containing multiple collections), or as a multi-arity function call.
union([{1, 2}, [2, 3], 1..4, "abc"])
union({1, 2}, [2, 3], 1..4, "abc")
intersection
intersection(..values)
Return the elements (as a Set) which are found in all the provided collections. The collections can be supplied as a single argument List (containing multiple collections), or as a multi-arity function call.
intersection([{1, 2}, [2, 3], 1..4])
intersection({1, 2}, [2, 3], 1..4)
rotate
rotate(steps, collection)
Rotate a given List a number of steps. If the step number is positive the rotation proceed forward, with the last item moving to the start of the List. If the step number is negative the rotation will go backwards, with the first item moving to the end of the List.
rotate(1, [1, 2, 3])
rotate(-1, [1, 2, 3])
chunk
chunk(size, collection)
Split a List into chunks based on a given size. If the List size is not divisible by the chunk size then the last chunk will contain fewer than the desired elements.
chunk(2, [1, 2, 3])
chunk(2, [1, 2, 3, 4])
combinations
combinations(size, collection)
Generate a Lazy Sequence which produces all the possible combinations of a desired number of elements from within a List.
combinations(2, [1, 2, 3, 4, 5]) |> list
combinations(3, [1, 2, 3, 4, 5]) |> find(|x| sum(x) == 10)
includes?
includes?(collection, value)
Predicate to assert if a value is present within a given collection, based on equality rules.
includes?([1, 2], 1)
includes?({1, 2}, 1)
Each character is considered an element.
includes?("ab", "a")
includes?(1..5, 1)
includes?(1..=5, 1)
includes?(1.., 5)
includes?(iterate(_ + 1, 1), 5)
excludes?
excludes?(collection, value)
Predicate to assert if a value is not present within a given collection, based on equality rules.
excludes?([1, 2], 3)
excludes?({1, 2}, 3)
Each character is considered an element.
excludes?("ab", "c")
excludes?(1..5, 6)
excludes?(1..=5, 6)
any?
any?(predicate, collection)
Predicate to assert if any value within the collection holds truthy based on the supplied pure predicate
function.
any?(_ == 1, [1, 2])
any?(_ == 1, {1, 2})
Each character is considered an element.
any?(_ == "a", "ab")
any?(_ == 1, 1..5)
any?(_ == 1, 1..=5)
any?(_ == 1, 1..)
any?(_ == 1, iterate(_ + 1, 1))
all?
all?(predicate, collection)
Predicate to assert if all values within the collection hold truthy based on the supplied pure predicate
function.
all?(_ > 0, [1, 2])
all?(_ > 0, {1, 2})
Each character is considered an element.
all?(_ != "c", "ab")
all?(_ > 0, 1..5)
all?(_ > 0, 1..=5)
Math
abs
abs(value)
Return the absolute value of a number.
abs(-1)
abs(-1.5)
vec_add
vec_add(a, b)
Sum two Lists together using Vector addition. The resulting List will contain results up to the shortest List's size.
vec_add([1, 2], [3, 4])
vec_add([1, 2, 3], [4, 5, 6])
signum
signum(value)
Return the sign (-1, 0, 1
) for the given number.
signum(5)
signum(-5.5)
Bitwise
bit_and
bit_and(a, b)
Return an Integer whose binary representation has a 1 in each bit position for which the corresponding bits of both operands are 1.
bit_and(9, 11) // 1001 & 1011
bit_or
bit_or(a, b)
Return an Integer whose binary representation has a 1 in each bit position for which the corresponding bits of either or both operands are 1.
bit_or(9, 11) // 1001 | 1011
bit_xor
bit_xor(a, b)
Return an Integer whose binary representation has a 1 in each bit position for which the corresponding bits of either but not both operands are 1.
bit_xor(9, 11) // 1001 ^ 1011
bit_shift_left
bit_shift_left(value, shift)
Return an Integer whose binary representation is the first operand shifted by the specified number of bits to the left.
bit_shift_left(1, 3)
bit_shift_right
bit_shift_right(value, shift)
Return an Integer whose binary representation is the first operand shifted by the specified number of bits to the right.
bit_shift_right(64, 3)
String
int
int(value)
Attempt to parse the provided value into an Integer representation.
int(5)
int(-5.5)
int("5")
int(true)
Upon failure to parse the value the Integer 0
is returned.
int("invalid")
ints
ints(value)
Return all parseable Integer values (as per int
) from a String value as a List.
If no Integers are found and empty List is returned.
ints("1,2,3")
ints("15a20b35")
lines
lines(value)
Split a given String into a List of Strings, seperated on new lines \n
.
lines("a\nb\nc")
split
split(seperator, value)
Split a given String into a List of Strings, seperated based on the provided value.
split("-", "a-b-c")
regex_match
regex_match(pattern, value)
Match and capture values from a subject String based on a provided Regular Expression. Captured values are returned as a List of Strings. If no match/capture can be found an empty List is returned.
regex_match("name: (\\w+), age: (\\d+)", "name: Bob, age: 30")
regex_match_all
regex_match_all(pattern, value)
Match and capture all occurrences from a subject String based on a provided Regular Expression. Captured values are returned as a List of Strings. If no match/capture can be found an empty List is returned.
regex_match_all("\\w+: \\w+", "name: Bob, age: 30")
Miscellaneous
range
range(from, to, step)
Generate an Inclusive Range using a custom step value (not the default +1, -1).
range(1, 10, 2) |> list
id
id(value)
Return the value passed in as an argument.
id(5)
memoize
memoize(function)
Return a function which wraps a given pure function memoizing invocation calls for performance. This is a trade-off between space and time complexity.
let fibonacci = memoize |n| {
if (n > 1) {
fibonacci(n - 1) + fibonacci(n - 2)
} else {
n
}
};
fibonacci(30)
evaluate
evaluate(source)
Evaluates the provided String expression within a sandbox santa-lang interpreter.
evaluate("1.. |> filter(_ % 2) |> take(3)")
type
type(value)
Return the type of the given value as a String.
type(1)