Functions and Lambdas
Functions are values. The most common way to write one is a lambda.
Lambdas
\x -> x + 1
Lambdas can take multiple arguments:
\x y -> x + y
Rex also accepts the Unicode spellings λ and →.
Annotating lambda parameters
You can annotate parameters when you need to force a specific type:
\(x: i32) -> x + 1
Application
Function application is left-associative:
f x y
is parsed as:
(f x) y
This is why parentheses are important when an argument is itself an application.
Functions returning functions (currying)
let add = \x -> (\y -> x + y) in
(add 1) 2
Partial application
Because functions are curried, you can supply fewer arguments to get a new function back:
let add1 = (+) 1 in add1 41
Top-level functions (fn)
Top-level functions require an explicit type signature:
fn add : i32 -> i32 -> i32 = \x y -> x + y
This declares a function that takes an i32 and returns another function i32 -> i32.
Top-level fn declarations are mutually recursive, so they can reference each other:
fn even : i32 -> bool = \n ->
if n == 0 then true else odd (n - 1)
fn odd : i32 -> bool = \n ->
if n == 0 then false else even (n - 1)
even 10
Legacy fn header forms
The parser still accepts older forms that put parameter names/types in the header:
fn inc (x: i32) -> i32 = x + 1
fn inc x: i32 -> i32 = x + 1
For multiple parameters, the “named arrows” form looks like:
fn add x: i32 -> y: i32 -> i32 = x + y
fn constraints with where
Top-level functions can also have type-class constraints:
fn sum_list : List i32 -> i32 where Foldable List = \xs -> foldl (+) 0 xs
If you haven’t seen where constraints before, Section 2 covers them in detail.