Blocks

Block Construction and Merging

FunctionDescription
symCreate symbol with name given by string s
mergeShallow merge block b2 on top of b1
deep-mergeDeep merge block b2 on top of b1, merges nested blocks but not lists
block?True if and only if v is a block
list?True if and only if v is a list
number?True if and only if v is a number
string?True if and only if v is a string
symbol?True if and only if v is a symbol
bool?True if and only if v is a boolean
type-data?True if and only if v is a type-data literal produced by the s prefix
elementsExpose list of elements of block b
block(re)construct block from list kvs of elements
has(s, b)True if and only if block b has key (symbol) s
lookup(s, b)Look up symbol s in block b, error if not found
lookup-in(b, s)Look up symbol s in block b, error if not found
lookup-or(s, d, b)Look up symbol s in block b, default d if not found
lookup-or-in(b, s, d)Look up symbol s in block b, default d if not found
(l ~ r)A ~ :k - safe key lookup. Returns value at key :k if a is a block containing :k, else null. Null-propagating for chained navigation
lookup-alts(syms, d, b)Look up symbols syms in turn in block b until a value is found, default d if none
lookup-across(s, d, bs)Look up symbol s in turn in each of blocks bs until a value is found, default d if none
lookup-path(ks, b)Look up value at key path ks in block b

Block Utilities

FunctionDescription
merge-all(bs)Merge all blocks in list bs together, later overriding earlier
keyReturn key in a block element / pair
valueReturn value in a block element / pair
keys(b)Return keys of block b
values(b)Return values of block b
sort-keys(b)Return block b with keys sorted alphabetically
pair-key-lt(p1, p2)
bimap(f, g, pr)Apply f to first item of pair and g to second, return pair
map-first(f, prs)Apply f to first elements of all pairs in list of pairs prs
map-second(f, prs)Apply f to second elements of all pairs in list of pairs prs
map-kv(f, b)Apply f(k, v) to each key / value pair in block b, returning list
map-elements(f, b)Apply f([k, v]) to each element of block b, returning a new block. f receives and should return a [key, value] pair
map-as-block(f, syms)Map each symbol in syms and create block mapping syms to mapped values
pair(k, v)Form a block element from key (symbol) k and value v
kv-block(k, v)Create a single-entry block from key k and value v
zip-kv(ks, vs)Create a block by zipping together keys ks and values vs
with-keysCreate block from list of values by assigning list of keys ks against them
map-values(f, b)Apply f(v) to each value in block b
map-keys(f, b)Apply f(k) to each key in block b
filter-items(f, b)Return items from block b which match item match function f
by-key(p?)Return item match function that checks predicate p? against the (symbol) key
by-key-name(p?)Return item match function that checks predicate p? against string representation of the key
by-key-match(re)Return item match function that checks string representation of the key matches regex re
by-value(p?)Return item match function that checks predicate p? against the item value
match-filter-values(re, b)Return list of values from block b with keys matching regex re
filter-values(p?, b)Return items from block b where values match predicate p?
select(ks, b)Return block containing only keys listed in ks. b select([:a, :c]) returns a sub-block with just those keys
dissoc(ks, b)Return block with keys listed in ks removed. b dissoc([:a, :c]) returns a sub-block without those keys

Block Alteration

FunctionDescription
alter-value(k, v, b)Alter b.k to value v
update-value(k, f, b)Update b.k to f(b.k)
alter(ks, v, b)In nested block b alter value to value v at path-of-keys ks
update(ks, f, b)In nested block b apply f to value at path-of-keys ks
update-value-or(k, f, d, b)Set b.k to f(v) where v is current value, otherwise add with default value d
set-value(k, v)Set b.k to v, adding if absent
tongue(ks, v)Construct block with a single nested path-of-keys ks down to value v
merge-at(ks, v, b)Shallow merge block v into block value at path-of-keys ks
deep-merge-at(ks, v, b)Deep merge block v into block value at path-of-keys ks

Deep Find and Query

FunctionDescription
deep-find(k, b)Return list of all values for key k (a symbol) at any depth in block b, depth-first
deep-find-first(k, d, b)Return first value for key k (a symbol) at any depth in block b, or default d
deep-find-paths(k, b)Return list of key paths to all occurrences of key k (a symbol) at any depth in block b
deep-query-fold(pattern, b)Core query engine returning [path, value] pairs matching the dot-separated pattern in block b
deep-query(pattern, b)Query block b using dot-separated pattern string. * matches one level, ** matches any depth. Bare foo is sugar for **.foo
deep-query-first(pattern, d, b)Return first match for pattern in block b, or default d
deep-query-paths(pattern, b)Return list of key paths matching pattern in block b

Deep Find

Searches for a key at any nesting level:

config: {
  server: { host: "localhost" port: 8080 }
  db: { host: "db.local" port: 5432 }
}

hosts: config deep-find(:host)  # ["localhost", "db.local"]
first-host: config deep-find-first(:host, "unknown")  # "localhost"

Deep Query

Queries using dot-separated patterns with wildcards:

  • Bare name foo is sugar for **.foo (find at any depth)
  • * matches one level
  • ** matches any depth
data: {
  us: { config: { host: "us.example.com" } }
  eu: { config: { host: "eu.example.com" } }
}

# Find all hosts under any config
hosts: data deep-query("config.host")  # ["us.example.com", "eu.example.com"]

# Wildcard: any key at one level, then host
hosts: data deep-query("*.config.host")