Anonymous Functions

Anonymous (lambda) functions are first-class values. They can be stored in variables, passed as arguments, and returned from functions.

Syntax

def main() {
    let double = fn (x: Int) Int { return x * 2 }
    let triple = fn (x: Int) Int -> x * 3
    let add    = fn (a: Int, b: Int) -> a + b
    let greet  = fn () -> print("hi")
}

The return type can be inferred with ->. An explicit return type is written before ->:

def main() {
    let f = fn () Int -> 1     // explicit return type
    let g = fn () -> 1         // inferred return type
}

Anonymous functions cannot be immediately invoked:

(fn () { print("hi") })()    // SyntaxError

Closure restriction

Anonymous functions can only access global constants and top-level definitions. They cannot close over local variables from the enclosing function:

def main() {
    let x = 5
    let f = fn () Int { return x }    // UnknownSymbol: x is not accessible
}

Global constants are accessible:

const MESSAGE = "hi"
def main() {
    let a = fn () -> print(MESSAGE)
    a()    // prints hi
}

Anonymous functions also cannot reference sibling local fn values (one local fn cannot call another declared in the same function).

Higher-order functions

Passing anonymous functions to functions that accept function parameters:

def apply(f: Fn(Int) Int, x: Int) Int -> f(x)

def main() {
    print(apply(fn (n: Int) Int -> n * n, 5).Str())    // 25
}
def do_something(f: Fn(Int) Int) Int {
    return f(42)
}

def main() {
    let plus_one = fn (x: Int) Int { return x + 1 }
    print(do_something(plus_one).Str())    // 43
}

An anonymous function passed with a mismatched signature is a TypeError:

def apply(f: Fn(Int) Int) { ... }
apply(fn (x: Int) -> "")    // TypeError: Str returned, Int expected

Named functions as first-class values

Named functions can also be stored in variables and reassigned:

def inc(x: Int) Int -> x + 1
def add_two(x: Int) Int -> x + 2

def main() {
    let mut f = inc
    print(f(1).Str())    // 2
    f = add_two
    print(f(1).Str())    // 3
}