2. Core Functions
The core library holds every function whose name has no prefix, such as map,
+, and str. Prefixed names belong to other libraries, such as
time/now. See DUST for source notation, evaluation, and
special forms, and the Function Index for all callable entries.
Ordinary function arguments evaluate before the call. Functions can be passed
as values and called through apply. This page covers function calls,
equality, and booleans; the rest of the core library is grouped by area:
- Collections — Lists and maps: access, update, transformation, and generation.
- Order — Comparison, sorting, uniqueness, and grouping.
- Types — Type predicates, conversion, and formatting.
- Arithmetic — Operators and bounds.
- Collection library — Namespaced list, map, and path operations.
- Math library — Namespaced numeric operations.
- Hash library — Digests of DUST values.
- Random library — Seeded random generators.
Table of Contents
(apply function arguments) → value
Calls a function value with the elements of a list as its arguments.
Both operands are evaluated before the call.
The first must produce an ordinary function, and the second must produce a list or null.
A null argument list supplies no arguments.
A string naming a function is not a function value.
Special forms and macros cannot be called through apply.
The list elements are passed as values, without evaluating them again as source.
(let [increment (fn [x] (+ 1 .x))] (apply .increment [4]))
(let [increment (fn [x] (+ 1 .x))] (apply .increment [4]))
(= x) → boolean
(= x y) → boolean
(= x y more*) → boolean
Returns true if all supplied values are equal, otherwise false.
With one argument, returns true.
With no arguments, produces an arity error.
With two or more arguments, compares adjacent values from left to right.
The first unequal pair returns false without comparing later pairs.
If every pair is equal, returns true.
Each compared pair must have the same type.
A type mismatch in a pair being compared produces #err <mismatch type>.
Types are not checked in advance across all arguments.
For example, ( 1 2 "2")= returns false, but ( 1 1 "1")= produces a type error.
Integers and floats are different types, so ( 1 1.0)= produces a type error.
= is an ordinary function.
Its argument expressions are evaluated before comparison begins.
Short-circuiting skips comparisons, not argument evaluation.
Thus ( 1 2 (/ 1 0))= produces a division-by-zero error.
- Numbers of the same type compare by value.
- Links compare their signed 64-bit payloads; a link and an integer have different types.
- Lists compare positionally.
- Maps compare keys and values independently of member order.
- Functions compare by identity.
[(= 1) (= null) (= [1 2]) (= (fn [])) (= 1 1) (= 1 2) (= 1 1 1) (= 1 1 2) (= 1 2 1) (= 1 2 "2") (= 1 1 2 null) (= null null null) (= [1] [1] [1])]
(= 1) (= null) (= [1 2]) (= (fn [])) (= 1 1) (= 1 2) (= 1 1 1) (= 1 1 2) (= 1 2 1) (= 1 2 "2") (= 1 1 2 null) (= null null null) (= [1] [1] [1])
true true true true true false true false false false false true true
(let [a {x 1} b {x 1} c .a] (= .a .b))
(let [a {x 1} b {x 1} c .a] (= .a .b))
true
(let [a {x 1} b {x 1} c .a] (= .a .c))
(let [a {x 1} b {x 1} c .a] (= .a .c))
true
(let [f (fn [x] .x) g .f h (fn [x] .x)] (= .f .g))
(let [f (fn [x] .x) g .f h (fn [x] .x)] (= .f .g))
true
(let [f (fn [x] .x) g .f h (fn [x] .x)] (= .f .h))
(let [f (fn [x] .x) g .f h (fn [x] .x)] (= .f .h))
false
(let [f (fn [x] .x) g .f h (fn [x] .x)] (= .f a))
(let [f (fn [x] .x) g .f h (fn [x] .x)] (= .f a))
#err <mismatch type>
(let [f (fn [x] .x) g .f h (fn [x] .x)] (= [.f] [.g]))
(let [f (fn [x] .x) g .f h (fn [x] .x)] (= [.f] [.g]))
true
(let [f (fn [x] .x) g .f h (fn [x] .x)] (= [.f] [.h]))
(let [f (fn [x] .x) g .f h (fn [x] .x)] (= [.f] [.h]))
false
(let [f (fn [x] .x) g .f h (fn [x] .x)] (= {callback .f} {callback .g}))
(let [f (fn [x] .x) g .f h (fn [x] .x)] (= {callback .f} {callback .g}))
true
(not value) → boolean
Returns true if value is null or false, otherwise false.
2.4. Collections ↑
These core functions build, read, and transform lists and maps. Functions that change a
collection change it in place and return it; collections/copy makes a copy to change
instead. They are part of the
core library; see DUST for source notation, evaluation, and
special forms.
2.4.1. Collection Functions ↑
Pointers can be used where these list functions accept a list. Pointer segments are strings for keys and integers for indices.
| Function | Pointer behavior |
|---|---|
count, empty? |
Count segments or test for no segments |
first, second, last, nth |
Return one segment value |
rest, slice, take, drop |
Return a pointer containing the selected segments |
concat |
Return a pointer when the first argument is a pointer; list-first concatenation returns a list |
map, filter, reduce, some, every?, take-while, drop-while |
Iterate segment values and return the usual list-function result |
Pointers are values that do not change, so the functions that change a list, such as
lists/append, lists/reverse, and sort, reject pointers with #err <mismatch type>.
Unless stated otherwise, list operations that make a new list accept null as an empty list, and map operations that make a new map accept null as an empty map.
Functions that change a collection require a target of the stated collection type, not null.
Map keys are strings.
Callbacks receive existing values without copying. Their side effects are not undone.
(map f xs) → list
(map f xs lists*) → list
Returns a list of the results of applying f to corresponding elements of xs and any additional lists.
The function receives one argument from each input list.
Calls occur in sequence order and stop when the shortest input is exhausted.
The result is built eagerly. Inputs are lists, pointers, or null, with
null treated as an empty list.
[(map (fn [x] (strings/case upper .x)) [ada "straße" ""]) (map :+ [1 2] [10 20 30]) (map :+ [1 2] [10] [100 200]) (map :+ [1 2] [10 20] [100] [1000 2000]) (map (fn [x] (strings/case upper .x)) []) (map (fn [x] (strings/case upper .x)) null) (map :+ [1] null) (map (fn [x] [.x]) [1 2])]
(map (fn [x] (strings/case upper .x)) [ada straße ""]) (map :+ [1 2] [10 20 30]) (map :+ [1 2] [10] [100 200]) (map :+ [1 2] [10 20] [100] [1000 2000]) (map (fn [x] (strings/case upper .x)) []) (map (fn [x] (strings/case upper .x)) null) (map :+ [1] null) (map (fn [x] [.x]) [1 2])
[[ADA STRASSE ""] [11 22] [111] [1111] [] [] [] [[1] [2]]]
(reduce function initial list) → value
Starts with initial and calls function with the accumulator and each list
element, in list order. Each call's result becomes the next accumulator.
Returns the final accumulator. An empty list or null returns initial
without calling the function. The first argument must be an ordinary function
value and the third must be a list, pointer, or null. Errors stop reduction immediately: a call
that returns an #err value ends the reduction, and that value is the result.
(reduce :+ 0 [1 2 3]) (reduce :- 10 [1 2 3]) (reduce (fn [acc x] (strings/join [.acc .x] "")) "" [a b c]) (reduce :+ 9007199254740993 [1 1])
6 4 abc 9007199254740995
(reduce (fn [acc x] (/ 1 0)) seed []) (reduce :+ false null) (reduce :+ null [])
seed false null
(patch map changes*) → map
Applies JSON Merge Patch member semantics to map in place and returns the same map.
All arguments must be maps, checked before any patch is applied.
With no changes maps, returns map unchanged.
Applies changes maps from left to right. Within each map, processes keys in ascending Unicode order:
nullremoves the member. A missing member is a no-op.- A map recursively patches the corresponding map. A missing or non-map destination is replaced with an empty map first.
- Any other value replaces the member without copying. Lists are replaced whole, not patched element by element.
Omitted members are unchanged. Nested patch maps are traversed, not installed by reference.
Collects the keys of each patch map before visiting its members, then reads each value when its key is processed, ignoring keys since removed.
Patch sources that alias the target observe earlier mutations.
Encountering a cycle through patch maps produces #err <invalid value> before applying the cyclic member. Earlier writes are not undone.
(patch {} a b) merges into a fresh map, and (patch (collections/copy m shallow) changes) into a copy of m.
Neither is a deep copy of the changes: null-valued members are omitted and list values are shared.
Use put to store null as a value.
(let [m {a 1}] [(patch .m {a 2}) .m]) (patch {} {a {b 1}} {a {c 2}}) (patch {a 1} {a null})
[[{a 2} {a 2}] {a {b 1 c 2}} {}]
(patch {items [a b c] keep 1} {items [x null] missing null}) (patch {a 1} {a {b 2 gone null}}) (patch {a {b 1 c 2}} {a {b null}})
{items [x null] keep 1} {a {b 2}} {a {c 2}}
(count collection) → integer
Returns the number of list elements, pointer segments, map members, or Unicode string code points.
For null, returns zero.
For strings, count returns the number of Unicode code points. For example,
é猫 has two code points. The letter e followed by a combining acute accent
also counts as two code points.
(empty? collection) → boolean
Returns whether count is zero. Lists, pointers, maps, strings, and null are accepted.
(first list) → value
Returns the first element or pointer segment, or null when empty.
(rest list) → list
Returns a fresh sequence without the first element. A pointer produces a
pointer; an empty list produces [] and an empty pointer produces the root pointer.
(rest [a b c]) (rest [a]) (rest []) (rest null) (rest [a null false]) (rest [a [b c] {name Ada}]) (let [list [a b c]] [(rest .list) .list])
[[b c] [] [] [] [null false] [[b c] {name Ada}] [[b c] [a b c]]]
{boolean (rest false) extra (rest [a b] 1) map (rest {a 1 b 2}) missing (rest) number (rest 2) string (rest abc)}
#cases [{output #err <mismatch type> select string} {output #err <mismatch type> select map} {output #err <mismatch type> select number} {output #err <mismatch type> select boolean} {output #err <arity mismatch> select missing} {output #err <arity mismatch> select extra}]
(jsonptr text) → pointer
Converts RFC 6901 text to a pointer. The empty string gives the root pointer;
a nonempty string must start with / and contain only valid ~0 and ~1
escapes. Invalid text gives #err <invalid value>; a non-string gives
#err <mismatch type>.
(get root path) → value
(get root path default) → value
Returns the value selected by path in root, or default if an entry is missing.
Without default, a missing entry returns null.
A selected value of null or false is returned unchanged, not replaced by default.
get does not modify root or copy the selected value.
A missing key or out-of-range nonnegative list index returns the default, including during nested traversal.
An empty path returns root.
(get {name Ada} name) (get {settings {theme dark}} (jsonptr "/settings/theme")) (get {users [{name Ada} {name Bea}]} [users 1 name]) (get {} theme default)
Ada dark Bea default
(put root path value) → collection
Stores value at path in root in place and returns the same root collection.
Inserts or replaces a map entry, or replaces an existing list element.
A list index equal to its length appends one element. Larger indices are errors.
Values replace rather than merge, and null is stored rather than deleted.
Creates maps, never lists, for missing or null intermediate values.
Integer path segments require an existing list.
The root must be a map or list, not null.
An empty path is an error.
Path, type, and bounds errors leave the target unchanged.
value is stored without copying, so a collection reachable from more than one place shows the change in each.
Use collections/copy to change a copy instead.
(let [user {name Ada}] [(put .user name Bea) .user]) (put {settings {theme light}} (jsonptr "/settings/theme") dark) (put {users [{name Ada}]} [users 0 name] Bea)
[[{name Bea} {name Bea}] {settings {theme dark}} {users [{name Bea}]}]
(let [user {name Ada} changed (put (collections/copy .user) name Bea)] [.user .changed]) (let [root {settings {theme light}} changed (put (collections/copy .root) (jsonptr "/settings/theme") dark)] [.root .changed]) (let [root {users [{name Ada}]} changed (put (collections/copy .root shallow) [users 0 name] Bea)] [.root .changed]) (let [root {users [{name Ada}]} changed (put (collections/copy .root shallow) users [])] [.root .changed])
(let [user {name Ada} changed (put (collections/copy .user) name Bea)] [.user .changed]) (let [root {settings {theme light}} changed (put (collections/copy .root) (jsonptr "/settings/theme") dark)] [.root .changed]) (let [root {users [{name Ada}]} changed (put (collections/copy .root shallow) [users 0 name] Bea)] [.root .changed]) (let [root {users [{name Ada}]} changed (put (collections/copy .root shallow) users [])] [.root .changed])
[[{name Ada} {name Bea}] [{settings {theme light}} {settings {theme dark}}] [{users [{name Bea}]} {users [{name Bea}]}] [{users [{name Ada}]} {users []}]]
A change is visible through every value that shares the changed collection:
(let [original {profile {name Ada} settings {theme dark}} renamed (put (collections/copy .original shallow) profile {name Bea})] (put .renamed [settings theme] light) [.original .renamed])
(let [original {profile {name Ada} settings {theme dark}} renamed (put (collections/copy .original shallow) profile {name Bea})] (put .renamed [settings theme] light) [.original .renamed])
{profile {name Ada} settings {theme light}} {profile {name Bea} settings {theme light}}
(remove root path) → collection
Removes the entry selected by path from root in place and returns the same root collection.
Removes a map member or a list element, shifting later list elements left.
Empty parent collections are not removed.
A missing key, out-of-range nonnegative index, or missing or null intermediate value leaves root unchanged.
No containers are created.
The root must be a map or list, not null.
An empty path produces #err <invalid value>.
Path and type errors leave the target unchanged.
(let [m {a b}] [(remove .m a) .m]) (let [m {}] [(remove .m a) .m]) (let [m {a {b 1}}] [(remove .m (jsonptr "/a/b")) .m])
[[{} {}] [{} {}] [{a {}} {a {}}]]
(let [m {a 1 b 2} changed (remove (collections/copy .m) a)] [.m .changed]) (let [m {a {b 1 c 2}} changed (remove (collections/copy .m) (jsonptr "/a/b"))] [.m .changed]) (let [m {a {b 1 c 2}} changed (remove (collections/copy .m shallow) (jsonptr "/a/b"))] [.m .changed]) (let [xs [Ada Bea] changed (remove (collections/copy .xs) 0)] [.xs .changed])
(let [m {a 1 b 2} changed (remove (collections/copy .m) a)] [.m .changed]) (let [m {a {b 1 c 2}} changed (remove (collections/copy .m) (jsonptr "/a/b"))] [.m .changed]) (let [m {a {b 1 c 2}} changed (remove (collections/copy .m shallow) (jsonptr "/a/b"))] [.m .changed]) (let [xs [Ada Bea] changed (remove (collections/copy .xs) 0)] [.xs .changed])
[[{a 1 b 2} {b 2}] [{a {b 1 c 2}} {a {c 2}}] [{a {c 2}} {a {c 2}}] [[Ada Bea] [Bea]]]
(contains? root path) → boolean
Returns true if path selects a value in root, including null or false, otherwise false.
(contains? {x null} x) (contains? {<!x>} x) (contains? {} x)
(contains? {x null} x) (contains? <!x> x) (contains? {} x)
true true false
(contains? {a null} a) (contains? <!a> (jsonptr "/a")) (contains? {a {b 1}} [a b]) (contains? [a b] 1) (contains? {a 1} missing) (contains? {a {}} [a b]) (contains? [a b] 2) (contains? {a/b null} a/b) (contains? <!/a> ["/a"]) (contains? <!/a> (jsonptr "/~1a")) (contains? {users [{name null}]} [users 0 name]) (contains? {users [{name null}]} (jsonptr "/users/0/name")) (contains? {"" null} "") (contains? {} []) (contains? [] []) (contains? null a)
true true true true false false false true true true true true true true true false
{escaped-token (jsonptr "/~2") extra (contains? {} a false) list-key (contains? [a] ["0"]) map-index (contains? {a 1} [0.5]) missing (contains?) missing-path (contains? {}) negative-index (contains? [a] -1) path-type (contains? {a 1} true) scalar-intermediate (contains? {a 1} [a b])}
#cases [{output #err <mismatch type> select path-type} {output #err <invalid value> select negative-index} {output #err <invalid value> select escaped-token} {output #err <mismatch type> select map-index} {output #err <mismatch type> select list-key} {output #err <mismatch type> select scalar-intermediate} {output #err <arity mismatch> select missing} {output #err <arity mismatch> select missing-path} {output #err <arity mismatch> select extra}]
(keys map) → list
Returns the map's string keys in ascending Unicode order.
(values map) → list
Returns map values in the same ascending key order used by keys.
(pairs map) → list
Returns [key value] pairs in the same ascending key order used by keys.
(pairs {a 2 z 1}) (pairs {}) (pairs {a null}) (pairs null) (pairs {<!""> /a 1 a/b 2})
[[[a 2] [z 1]] [] [[a null]] [] [["" false] ["/a" 1] [a/b 2]]]
{extra (pairs {} {}) list (pairs [a 1]) missing (pairs) string (pairs abc)}
#cases [{output #err <mismatch type> select list} {output #err <mismatch type> select string} {output #err <arity mismatch> select missing} {output #err <arity mismatch> select extra}]
2.4.1.16. from-pairs ↑
Function(from-pairs list) → map
Returns a fresh map from [key value] pairs in list.
Later duplicate keys win.
(from-pairs [[b 2] [a 1]]) (from-pairs []) (from-pairs null) (from-pairs [[a 1] [b 2] [a 3]]) (from-pairs [[a 1] [a null] [b false]]) (from-pairs [["" 0] ["/a" 1] [a/b 2]]) (from-pairs [[nested {a 1}] [items [1 2]]]) (from-pairs (pairs {<!z> a null nested {b 2}})) (pairs (from-pairs [[z 1] [a 2] [z 3]]))
{a 1 b 2} {} {} {a 3 b 2} {<!b> a null} {"" 0 /a 1 a/b 2} {items [1 2] nested {a 1}} {<!z> a null nested {b 2}} [[a 2] [z 3]]
{empty-pair (from-pairs [[]]) extra (from-pairs [] []) later-invalid-pair (from-pairs [[a 1] [b]]) list-key (from-pairs [[[a] 1]]) long-pair (from-pairs [[a 1 2]]) map (from-pairs {a 1}) map-pair (from-pairs [{a 1}]) missing (from-pairs) non-pair (from-pairs [1]) null-key (from-pairs [[null a]]) null-pair (from-pairs [null]) number-key (from-pairs [[1 a]]) short-pair (from-pairs [[a]]) string (from-pairs abc) string-pair (from-pairs [ab])}
#cases [{output #err <mismatch type> select map} {output #err <mismatch type> select string} {output #err <mismatch type> select non-pair} {output #err <mismatch type> select map-pair} {output #err <mismatch type> select string-pair} {output #err <invalid value> select empty-pair} {output #err <invalid value> select null-pair} {output #err <invalid value> select short-pair} {output #err <invalid value> select long-pair} {output #err <mismatch type> select number-key} {output #err <mismatch type> select null-key} {output #err <mismatch type> select list-key} {output #err <invalid value> select later-invalid-pair} {output #err <arity mismatch> select missing} {output #err <arity mismatch> select extra}]
2.5. Ordering ↑
These core functions compare values, sort lists, remove duplicates, and group values by key. They are part of the core library; see DUST for source notation, evaluation, and special forms.
2.5.1. Ordering, uniqueness, and grouping ↑
(compare first second) → integer
Returns -1, 0, or 1 when first sorts before, ties with, or sorts after second, using sort ordering.
(compare 2 5) (compare 5 5) (compare 5 2) (compare a b) (compare 猫 é) (compare false true) (compare true false) (compare null null) (compare 1.5 2.5) (compare -0.0 0.0) (compare #link 2 #link 1) (compare 9007199254740992 9007199254740993)
(compare 2 5) (compare 5 5) (compare 5 2) (compare a b) (compare 猫 é) (compare false true) (compare true false) (compare null null) (compare 1.5 2.5) (compare 0.0 0.0) (compare #link 2 #link 1) (compare 9007199254740992 9007199254740993)
-1 0 1 -1 1 -1 1 0 -1 0 1 -1
{extra-argument (compare 1 2 3) functions (compare (fn [x] .x) (fn [x] .x)) lists (compare [1] [1]) maps (compare {a 1} {a 1}) mixed-numbers (compare 1 1.0) mixed-scalars (compare a 1) no-arguments (compare) null-and-value (compare null 1) one-argument (compare 1)}
#cases [{output #err <mismatch type> select mixed-numbers} {output #err <mismatch type> select mixed-scalars} {output #err <mismatch type> select null-and-value} {output #err <mismatch type> select lists} {output #err <mismatch type> select maps} {output #err <mismatch type> select functions} {output #err <arity mismatch> select no-arguments} {output #err <arity mismatch> select one-argument} {output #err <arity mismatch> select extra-argument}]
(sort list) → list
(sort comparator list) → list
Sorts list in place, stably, and returns the same list, without copying its elements.
The list's order changes only after all comparisons succeed.
list must be a list, not null or a pointer.
By default, sorts in ascending order and requires all elements to have the same kind.
Orderable kinds are null, boolean, integer, float, string, link, UTC, duration,
SHA-256, and pointer. Pointer segments compare lexicographically, with an
index before a key; a shorter prefix sorts before its extension. Integers and
nominal integer payloads compare exactly. Strings
compare by Unicode code point order, booleans put false before true, and
SHA-256 values compare their bytes. Null values tie.
Equal values keep their input order. With default ordering, compound values, functions, expression forms, and mixed kinds are errors, including in singleton lists.
A supplied comparator receives two elements and returns a negative integer, zero, or a positive integer when the first sorts before, ties with, or sorts after the second.
Custom comparators can order any element kinds.
A non-function comparator produces #err <expected function>. A non-integer result produces #err <mismatch type>.
Comparator errors stop sorting and are returned.
The comparator must define a consistent order and must not change the input list or the values being compared.
Its call order and call count are not guaranteed.
(sort [3 1 2]) (sort [猫 é a]) (sort [false true false]) (sort [#link 2 #link 1]) (sort [null null])
[[1 2 3] [a é 猫] [false false true] [#link 1 #link 2] [null null]]
(let [xs [3 1 2]] [(sort .xs) .xs]) (let [xs []] [(sort .xs) .xs]) (let [xs [2 1 2]] [(sort .xs) .xs])
[[[1 2 3] [1 2 3]] [[] []] [[1 2 2] [1 2 2]]]
(sort (fn [a b] (- .b .a)) [1 3 2]) (sort (fn [a b] (- (get .a rank) (get .b rank))) [{id a rank 2} {id b rank 1} {id c rank 2}])
[[3 2 1] [{id b rank 1} {id a rank 2} {id c rank 2}]]
(distinct list) → list
Returns a fresh list retaining the first occurrence of each distinct typed
value. Collections compare structurally, with map member order ignored.
Kinds remain distinct: integer 1 and float 1.0 are separate values.
Functions compare by identity. Positive and negative floating zero compare equal.
(distinct [1 1.0 1 1.0]) (distinct [{a 1 b 2} {a 1 b 2} [a] [a]]) (distinct [null false null false]) (let [f (fn [] 1) g (fn [] 1)] (count (distinct [.f .f .g])))
[[1 1.0] [{a 1 b 2} [a]] [null false] 2]
2.5.2. Ordered comparisons ↑
The ordered comparisons accept the same scalar kinds as sort and require
matching kinds. They require at least two arguments and validate every
argument's kind before comparing adjacent pairs from left to right. As ordinary
functions, all argument expressions evaluate before comparison begins.
(< first second more*) → boolean
Returns whether the arguments are strictly increasing.
(<= first second more*) → boolean
Returns whether the arguments are nondecreasing.
(> first second more*) → boolean
Returns whether the arguments are strictly decreasing.
(>= first second more*) → boolean
Returns whether the arguments are nonincreasing.
2.6. Types ↑
These core functions test and convert values. They are part of the core library; see DUST for source notation, evaluation, and special forms.
2.6.1. Type Predicates ↑
(error? value) → boolean
Returns true if value is an error and false otherwise. Errors can be
passed as arguments without losing their tags.
[(error? #err app/oh-no) (error? (/ 1 0)) (error? (= 1 1.0)) (error? (=)) (let [inspect :error?] (inspect (/ 1 0))) (error? null) (error? false) (error? true) (error? 0) (error? 1.0) (error? "") (error? dust/type-mismatch) (error? "#err dust/type-mismatch") (error? []) (error? {}) (error? {error dust/type-mismatch}) (error? (fn [] null)) (error? `.name)]
(error? #err app/oh-no) (error? (/ 1 0)) (error? (= 1 1.0)) (error? (=)) (let [inspect :error?] (inspect (/ 1 0))) (error? null) (error? false) (error? true) (error? 0) (error? 1.0) (error? "") (error? dust/type-mismatch) (error? "#err dust/type-mismatch") (error? []) (error? {}) (error? {error dust/type-mismatch}) (error? (fn [] null)) (error? `.name)
true true true true true false false false false false false false false false false false false false
(null? x) → boolean
Returns true if x is null, otherwise false.
[(null? null) (null? nil) (null? "null") (null? false)]
(null? null) (null? nil) (null? "null") (null? false)
true false false false
(string? s) → boolean
Returns true if s is a string, otherwise false.
[(string? nil) (string? "") (string? "42") (string? null) (string? 42)]
(string? nil) (string? "") (string? "42") (string? null) (string? 42)
true true true false false
(int? n) → boolean
Returns true if n is an integer, otherwise false.
A link scalar is not an integer.
[(int? 0) (int? -42) (int? 1.0) (int? 1e0) (int? "42") (int? (+ 1 2))]
(int? 0) (int? -42) (int? 1.0) (int? 1.0) (int? "42") (int? (+ 1 2))
true true false false false true
(float? n) → boolean
Returns true if n is a floating-point number, otherwise false.
[(float? 1.0) (float? 1e0) (float? 1) (float? "1.0")]
(float? 1.0) (float? 1.0) (float? 1) (float? "1.0")
true true false false
(number? n) → boolean
Returns true if n is an integer or a float, otherwise false.
A link scalar is not a number.
[(number? 1) (number? 1.5) (number? "1") (number? true) (number? null)]
(number? 1) (number? 1.5) (number? "1") (number? true) (number? null)
true true false false false
(jsonptr? value) → boolean
Returns true for a pointer and false for other values. A pointer is not a
list, even though the list functions accept it.
(jsonptr? /a) ; true
(jsonptr? "/a") ; false
(list? xs) → boolean
Returns true if xs is a list, otherwise false.
[(list? []) (list? [1]) (list? {}) (list? null)]
(list? []) (list? [1]) (list? {}) (list? null)
true true false false
(map? m) → boolean
Returns true if m is a map, otherwise false.
[(map? {}) (map? {name Ada}) (map? []) (map? null)]
(map? {}) (map? {name Ada}) (map? []) (map? null)
true true false false
(boolean? b) → boolean
Returns true if b is either true or false, otherwise false.
[(boolean? true) (boolean? false) (boolean? null) (boolean? "true") (boolean? 0)]
(boolean? true) (boolean? false) (boolean? null) (boolean? "true") (boolean? 0)
true true false false false
(template? value) → boolean
Returns true if value is a string template, otherwise false.
(let [t (templates/from-parts {strings ["hello-" ""] values [Ada]})] [(template? .t) (string? .t) (template? "hello-Ada") (templates/parts .t) (str .t) (strings/starts-with? .t hello) (= .t "hello-Ada") (count .t) (strings/join [.t "!"] "") (compare .t "hello-Ada") (get {hello-Ada 42} .t)]) (templates/render (templates/from-parts {strings ["hello-" ""] values ["<Ada>"]}) {escape (strings/escape html-text)}) (let [name Ada] #template [["hello-" ""] [.name]]) #template [["outer-" ""] [#template [["inner-" ""] [Ada]]]]
(let [t (templates/from-parts {strings [hello- ""] values [Ada]})] [(template? .t) (string? .t) (template? hello-Ada) (templates/parts .t) (str .t) (strings/starts-with? .t hello) (= .t hello-Ada) (count .t) (strings/join [.t !] "") (compare .t hello-Ada) (get {hello-Ada 42} .t)]) (templates/render (templates/from-parts {strings [hello- ""] values ["<Ada>"]}) {escape (strings/escape html-text)}) (let [name Ada] ~"hello-,.name") ~"outer-,~"inner-,Ada""
[[true true false {strings [hello- ""] values [Ada]} hello-Ada true true 9 hello-Ada! 0 42] hello-<Ada> hello-Ada outer-inner-Ada]
(fn? f) → boolean
Returns true if f is a function, otherwise false.
[(fn? (fn [] null)) (fn? :+) (fn? +) (fn? [])]
(fn? (fn [] null)) (fn? :+) (fn? +) (fn? [])
true true false false
(local? v) → boolean
Returns true if v is a local reference, such as the quoted form
`.name, otherwise false.
[(local? `.name) (local? `:name) (local? ".name") (local? name)]
(local? `.name) (local? `:name) (local? ".name") (local? name)
true false false false
(const? v) → boolean
Returns true if v is a constant reference, such as the quoted form
`:name, otherwise false. A local and a constant with the same name are
not equal.
[(const? `:math/pi) (const? `.math/pi) (const? :math/pi) (const? ":math/pi")]
(const? `:math/pi) (const? `.math/pi) (const? :math/pi) (const? ":math/pi")
true false false false
2.6.2. Type Conversion ↑
(int value) → integer
Returns an integer unchanged, truncates a float toward zero, or parses a signed decimal string exactly. String input accepts an optional ASCII sign followed by ASCII decimal digits, including leading zeros. Whitespace, decimal points, exponents, and hexadecimal notation are rejected. Values outside signed 64-bit range are errors. Booleans, null, and nominal types such as links are rejected.
(int "9007199254740993") (int -1.9) (int +00042) (int "-9223372036854775808")
9007199254740993 -1 42 -9223372036854775808
(float value) → float
Converts an integer to a float, returns a float unchanged, or parses a signed
decimal string with an optional decimal point and exponent. Integer conversion
can lose precision; for example, integer 9007199254740993 converts to
9007199254740992.0. Whitespace, hexadecimal notation, NaN, and infinity are
rejected. Overflow is an error; underflow to zero is permitted. Booleans, null,
and nominal types such as links are rejected.
(str values*) → string
Converts zero or more values to strings and concatenates them in argument order.
It inserts no spaces or other separators.
With no arguments, returns the empty string.
Strings contribute their contents without added quotes or escaping.
A null argument contributes the empty string.
Numbers and booleans use their RON representations.
Lists, maps, and representable tagged values use canonical RON formatting.
RON has one canonical format; layout follows its normal formatting rules.
The formatter appends no terminal newline, and str uses those canonical bytes
unchanged. Internal line breaks in formatted collections are retained.
Collections are printed as complete values, not flattened into arguments.
Within collections, null is printed as null and strings are quoted when required to preserve their values.
str is an ordinary function.
Its arguments are evaluated before conversion.
String contents are text and are not interpreted as expressions.
(str) ; => ""
(str a null b) ; => "ab"
(str order- 42 .json) ; => "order-42.json"
(do [ (str [null "null" 1 true]) (str {z 2 a 1}) (str `.name) (str #utc 2026-10-24T12:34:56Z) ])
(do [(str [null "null" 1 true]) (str {a 1 z 2}) (str `.name) (str #utc 2026-10-24T12:34:56Z)])
""[null "null" 1 true]"" """ a 1 z 2 """ "#local name" "#utc 2026-10-24T12:34:56Z"
(boolean value) → boolean
Returns false if value is null or false, otherwise true.
(format template args*) → string
Returns a string by substituting args into the conversion specifications in template.
The syntax is printf-style. DUST supports %v for value conversion and
requires the argument types below.
A conversion has the form %[flags][width][.precision]conversion.
Each conversion consumes one argument in order, except %%, which consumes none.
Other text is copied unchanged.
The string template contains no embedded expressions.
| Conversion | Argument | Result |
|---|---|---|
s |
String | String contents |
v |
Any value | Text produced by str |
d, i |
Integer | Signed decimal |
o |
Integer | Unsigned octal |
x, X |
Integer | Unsigned hexadecimal, lowercase or uppercase |
f |
Float | Fixed-point decimal |
e, E |
Float | Scientific notation with e or E |
g, G |
Float | Compact decimal or scientific notation |
% |
None | A literal percent sign, written %% |
Width is a decimal minimum field width. Padding uses spaces on the left by default and never truncates a value. Width counts UTF-8 bytes, not code points or display columns.
| Flag | Applies to | Effect |
|---|---|---|
- |
All except % |
Left-align within the field |
+ |
Signed decimal and floats | Always include a sign |
| Space | Signed decimal and floats | Prefix nonnegative values with a space |
0 |
Numeric conversions | Pad with zeros after any sign or base prefix |
# |
o, x, X |
Alternate form with an octal or hexadecimal prefix |
# |
Floats | Keep the decimal point, and keep trailing zeros for g and G |
The + flag overrides the space flag, and - overrides 0.
Integer precision also overrides 0.
Flags not applicable to a conversion are errors.
Precision is a decimal count after ., with an omitted count meaning zero.
For integers it sets the minimum digit count.
For f, e, and E it sets the fractional digit count, defaulting to six.
For g and G it sets the significant digit count, defaulting to six, with zero treated as one.
These numeric conversions follow C printf formatting rules, including rounding and alternate forms.
Precision is not supported for s or v.
The %% escape accepts no flags, width, or precision.
Integer formatting preserves all 64 bits without conversion through a float.
Octal and hexadecimal conversions interpret negative integers modulo 2^64.
Floating-point formatting rounds the stored binary value, not an exact decimal value.
Numeric output uses . as the decimal point and no locale-specific grouping.
There is no implicit numeric conversion: %.2f requires a float, so integer 42 is an error.
The s conversion requires a string, while v accepts any value, including null as the empty string.
Dynamic width or precision (*), positional arguments ($), length modifiers,
and conversions not listed above are unsupported.
Invalid specifications produce #err <invalid value>.
An incompatible argument type, including a non-string template, produces #err <mismatch type>.
Missing or extra arguments produce #err <arity mismatch>.
Formatting, field widths, and precision are subject to the execution and output resource limits.
(format "Hello, %s!" Ada) (format "Invoice %04d: %.2f EUR" 7 12.5) (format "Progress: %d%%" 75) (format "Result: %v" {count 3})
"Hello, Ada!" "Invoice 0007: 12.50 EUR" "Progress: 75%" "Result: {count 3}"
2.7. Arithmetic ↑
These core functions provide arithmetic. They are part of the core library; see DUST for source notation, evaluation, and special forms.
2.7.1. Arithmetic ↑
Arithmetic proceeds from left to right.
Links are not numbers and are rejected by numeric operations.
Numbers never convert implicitly: the numeric operands of one call must be all
integers or all floats, and an integer paired with a float is a type mismatch.
Convert explicitly with float or int.
Integer overflow and non-finite floating-point results are errors.
The shared operators also support the explicit temporal combinations below. UTC and duration values retain their nominal types and signed 100 ns tick precision. A number never becomes an implicit duration.
| Operation | Result |
|---|---|
| UTC + duration; duration + UTC | UTC |
| Duration + duration | Duration |
| UTC - duration | UTC |
| UTC - UTC; duration - duration | Duration |
| Duration * integer; integer * duration | Duration |
| Duration / integer | Duration, truncated toward zero |
| Duration / duration | Float ratio |
Other temporal combinations are type errors. See the Time library for temporal examples and bounds.
(+) → integer
(+ value) → value
(+ value other more*) → value
Returns the sum of its arguments.
With no arguments, returns 0.
With one argument, returns that numeric or temporal value unchanged.
[(+) (+ 7) (+ 1 2 3) (+ 1.0) (+ 1.0 2.5) (+ -2 2)]
(+) (+ 7) (+ 1 2 3) (+ 1.0) (+ 1.0 2.5) (+ -2 2)
0 7 6 1.0 3.5 0
(- value more*) → value
With one argument, returns its negation. With additional arguments, subtracts each from the running result in order. At least one argument is required. Numeric operands follow the arithmetic rules above; temporal operands use the combinations in the table. Integer overflow and non-finite floating-point results are errors, including when negating the minimum integer. Unary subtraction also negates durations; UTC timestamps cannot be negated.
(- 3) (- 10 3 2) (- 10.0 2.5) (- -9007199254740993) (- 9007199254740995 1 1) (- 0)
-3 5 7.5 9007199254740993 9007199254740993 0
(*) → integer
(* value) → value
(* value other more*) → value
Returns the product of its arguments.
With no arguments, returns 1.
With one argument, returns that number or duration unchanged.
[(*) (* 7) (* 2 3 4) (* 1.0) (* 2.0 1.5) (* -2 0)]
(*) (* 7) (* 2 3 4) (* 1.0) (* 2.0 1.5) (* -2 0)
1 7 24 1.0 3.0 0
(/ n) → float
(/ value divisor more*) → value
Returns n divided by d and each additional divisor in more, or the reciprocal of n when called with one argument.
Numeric operands must be all integers or all floats. Numeric division proceeds from left to right and always returns a float, even for integer operands. Duration division follows the temporal combinations in the table above. A zero divisor is an error. A duration requires a divisor; unary duration reciprocals are not defined.
[(/ 2) (/ 6 3) (/ 1 2) (/ 24 2 3) (/ -2) (/ 1 3) (/ 1.0 2.0) (/ 0 2)]
(/ 2) (/ 6 3) (/ 1 2) (/ 24 2 3) (/ -2) (/ 1 3) (/ 1.0 2.0) (/ 0 2)
0.5 2.0 0.5 4.0 -0.5 0.3333333333333333 0.5 0.0
(rem dividend divisor) → number
Returns the remainder with the sign of the dividend. Two integers produce an
exact integer remainder; otherwise the result is a float. A zero divisor is an
error. The minimum integer divided by -1 has remainder zero.