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.

wcl
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.