8. Functions and higher-order patterns
Named fn items, fn literals, and the map/filter/fold trio.
After this lesson you can
- Declare a named function with fn name(...) -> T { ... } - Pass fn literals to map, filter, and fold - Decide when computation belongs in the document
Before you start: Optionals, unions, and match
Functions are first-class values. A named fn item declares a reusable function at file scope; an inline literal (fn(n: i64) -> bool { n % 2 == 0 }) is handy exactly where a builtin wants a callback. Parameters and returns are typed, like everything else.
The workhorse trio: map transforms each element, filter keeps the ones a predicate accepts, fold reduces a list to one value from an initial accumulator. Together with let items (file-scope bindings that are visible to expressions but invisible to the document), they let a configuration *derive* values instead of repeating them.
§ 1Exercise: Derive, don't repeat
From one list of numbers, derive a doubled list, the even subset, and a total.
fn double(n: i64) -> i64 { n * 2 }
let nums = [1, 2, 3, 4, 5]
let evens = filter(nums, fn(n: i64) -> bool { n % 2 == 0 })
@document
type Doc {
doubled: list<i64>
even: list<i64>
total: i64
}
doubled = map(nums, double)
even = evens
total = fold(nums, 0, fn(acc: i64, n: i64) -> i64 { acc + n })
Expected result
wcl eval doc.wcl doubled prints [2, 4, 6, 8, 10] and wcl eval doc.wcl total prints 15.
Hint
let items like nums never appear in the evaluated document — only the declared fields do. That's why the schema doesn't mention them.