8. Lambdas and the effect system
An anonymous function is written (params) => expr — a single un-annotated parameter
may drop the parentheses and be written x => expr, and a parameter annotation may be
left out wherever the type can be inferred. A function type is written
fn(A) -> B !e, where !e is its effect. A pure function's signature is enough to know
it has no side effects, and a test for one needs no mocks.
pub fn main() -> Unit !io = {
let nums = [1, 2, 3, 4]
let evens = filter(nums, n => n % 2 == 0)
let doubled = map(evens, n => n * 2)
println(to_string(doubled))
}
Open in playground
[4, 8]
A higher-order function forwards its arguments' effects through an effect variable:
the effect of map(f) is the effect of f. The union of two function parameters'
effects is written !(e1 | e2) — pure ∘ pure is still pure, and anything that touches
io is io.
fn compose[A, B, C](f: fn(A) -> B !e1, g: fn(B) -> C !e2) -> fn(A) -> C !(e1 | e2) =
a => g(f(a))
fn inc(x: Int) -> Int = x + 1
fn dbl(x: Int) -> Int = x * 2
pub fn main() -> Unit !io = {
let f = compose(inc, dbl)
println(to_string(f(10)))
}
Open in playground
22