Lambdas

Lambdas

A lambda is a value wrapping a function and its closure.
This is useful to be able to customize a function by passing in behaviors and not just values.
For example, filter can filter a collection by any arbitrary predicate.
A lambda value is created using the => syntax.

main void() xs nat[] = 1, 2, 3 ys nat[] = xs filter x => x is-even info log "{ys.to::json}"

There is a subscript function for calling lambdas, called like f[x].

main void() info log ((x => "{x}") foo) foo string(a string data(x nat)) a[1]

The syntax void data(x nat) defines a lambda type. The lambda returns void and takes a nat. The parameter name x is just for documentation. data will be explained in the section on Closures.

Parameter destructuring

All lambdas take one parameter, but it can be a tuple.

main void() info log (((x, y) => "{x} {y}") foo) () foo string(a string data(x nat, y nat)) # Constructs a tuple (1, 2) to pass to 'subscript' a[1, 2]

The syntax makes it look like there are multiple parameters. To show that it's really only one parameter:

main void() info log ((tuple => "{tuple.a} {tuple.b}") foo) foo string(a string data(x nat, y nat)) tuple (nat, nat) = 1, 2 a[tuple]

Similarly, a lambda can appear to take no parameter, but it actually takes void.

main void() info log ((() => "hello") foo) foo string(a string data()) # This is the same as 'a[()]'. a[]

Closures

The code inside the lambda body (after the =>) can access variables outside. Those variables are called its closure.

main void() factor nat = 2 f nat data(x nat) = x => x * factor info log "{f[3]}"

Closure purity

The data keyword is the purity of the closure. To allow the closure to include shared or mut data, use that keyword in the lambda type instead of data.

main void() factor mut nat = 2 f nat mut(x nat) = x => x * factor factor := 4 info log "{f[3]}"

Most ordinary functions in the standard library allow a mut closure.

Multi-line lambdas

If a lambda's body is long, you can put it in an indented block.

main void() xs nat[] = 1, 2, 3, 4, 5, 6 ys nat[] = xs filter x => if x > 3 x is-even else x is-odd info log "{ys.to::json}"

Since this is only possible for the last argument to a funciton, most functions make sure a lambda argument comes last.

Lambdas in records

If a record has a lambda field, it generates a "caller" that gets the lambda and calls it.
(It also generates a getter as usual.)

main void() r r = do greet: x => info log "Hello, {x}!" # Equivalent to 'r.greet["world"]' r greet "world" r record mut greet void mut(x string)