Rat docs

Collections

Seventeen array builtins. The first five (range, sum, avg, sort, first/last) cover the common slicing-and-aggregating cases without writing a loop. push/pop are immutable helpers (the call returns a new array; the source is untouched). filter/map/reduce take lambdas — Rat's fn >> expr spelled inline at the call site. The rest is sugar — group_by, count_by, unique, flatten, chunk, zip — for the shape conversions that show up over and over in real apps.

range — generate a sequence

1, 2, or 3-arg forms

range(n) is [0, 1, ..., n-1]. range(start, end) is the half-open interval. range(start, end, step) walks with a step (the step can be negative for descending).

<p> [range(5)]
<p> [range(2, 6)]
<p> [range(0, 10, 3)]
Result

[0, 1, 2, 3, 4]

[2, 3, 4, 5]

[0, 3, 6, 9]

sum / avg — numeric aggregation

Empty array → 0

sum(arr) totals the values; avg(arr) returns the mean. Both expect numeric elements and return 0 on an empty array — guard upstream if "no data" must read differently from "data sums to zero".

<p> [sum(nums)]
<p> [avg(nums)]
Result

sum: 150

avg: 30

sort — stable ascending

Returns a new array; source unchanged

sort(arr) returns a new array sorted in ascending order using the default comparator (numbers numerically, strings lexicographically). It's stable, so equal keys keep their input order. For descending or custom orderings, sort then call reduce with the order you want, or use a small helper.

<p> [sort([3, 1, 4, 1, 5, 9])]
Result

[1, 1, 3, 4, 5, 9]

first / last — head and tail

One-arg form returns the element; two-arg returns N

first(arr) returns the first element (or null on empty); first(arr, n) returns the first n elements as an array. last is symmetric.

<p> [first(items)]
<p> [last(items)]
<p> [first(nums, 2)]
<p> [last(nums, 2)]
Result

first(items) = apples

last(items) = figs

first(nums, 2) = [10, 20]

last(nums, 2) = [40, 50]

push / pop — immutable wrappers

Returns a new array; for in-place use .add() / .pop() on state

push(arr, value) returns a new array with the value appended; pop(arr) returns the last element. Neither mutates the input — for in-place writes on page state, use name.add(v) / name.pop() in a handler instead.

<p> [push(items, 'kiwi')]
<p> [pop(items)]
Result

push: [apples, pears, figs, kiwi]

pop: figs

filter — keep matching elements

Lambda predicate; keeps truthy returns

filter(arr, lambda) returns the elements for which the lambda returns truthy. The lambda is one-arg; for index-aware filters write a custom reduce or use map first to attach indices.

<p> [filter(nums, [x] >> x > 20)]
Result

[30, 40, 50]

map — transform each element

Lambda returns the new element

map(arr, lambda) applies the lambda to each element and collects the results into a new array. The lambda can return any value — number, string, object — and the output array adopts whatever shape it returns.

<p> [map(nums, [x] >> x + 1)]
Result

[11, 21, 31, 41, 51]

reduce — fold to a single value

Lambda is (accumulator, element); third arg is the seed

reduce(arr, lambda, init) folds the array. The lambda takes the running accumulator and the current element; the third arg seeds the accumulator. Common idiom: build a histogram with reduce(arr, [acc, x] >> set_field(acc, x, get_or(acc, x, 0) + 1), {}) — though for the histogram case count_by is shorter.

<p> [reduce(nums, [a, b] >> a + b, 0)]
Result

150

group_by — bucket by key

Returns an object: key → array of matching elements

group_by(arr, lambda) calls the lambda on each element and groups elements with equal lambda results into the same bucket. The result is an object — iterate with in keys(result) if you need the bucket name alongside the bucket.

<p> [group_by(nums, [x] >> x > 25)]
Result

{false: [10, 20], true: [30, 40, 50]}

count_by — histogram

Object: key → count

count_by(arr, lambda) is group_by + len on each bucket. Use it for cheap frequency counts — word length distributions, status code tallies, anything where you want "how many fell into each category".

<p> [count_by(items, [w] >> len(w))]
Result

{6: 1, 5: 1, 4: 1}

unique — deduplicate

Preserves first-seen order

unique(arr) removes duplicate elements, keeping the first occurrence of each. Useful for cleaning up tag lists, recipient sets, or any "list of distinct" output.

<p> [unique([1, 2, 2, 3, 1])]
Result

[1, 2, 3]

flatten — one level of nesting

arr of arrs → flat arr

flatten(arr) concatenates the inner arrays into one. It strips exactly one level — call it twice for two-deep, or write a recursive helper for arbitrary depth. The shallow form is deliberate; most real data is one-deep and a generic deep-flatten loses type structure.

<p> [flatten([[1, 2], [3], [4, 5]])]
Result

[1, 2, 3, 4, 5]

chunk — fixed-size sub-arrays

Last chunk may be shorter

chunk(arr, n) splits the array into sub-arrays of length n. The last chunk is shorter than n if the array doesn't divide evenly. Useful for paginating, rendering grids row by row, or batching API calls.

<p> [chunk(range(7), 3)]
Result

[[0, 1, 2], [3, 4, 5], [6]]

zip — tuple-merge two arrays

Result length = shorter input

zip(a, b) pairs up elements by index, producing an array of two-element arrays. If the inputs are different lengths, the longer one is truncated. Pair with map when you need a record shape: map(zip(keys, values), >> {k: pair0, v: pair1}).

<p> [zip([1, 2, 3], ['a', 'b', 'c'])]
Result

[[1, a], [2, b], [3, c]]

Next: Encoding — base64, URL, hex round-trips.