Anonymous functions

Anonymous functions (also called lambdas) let you define functions inline without naming them. They're useful for quick one-off operations and callbacks.

Basic syntax

Use fn (signature) { body } to create an anonymous function:

fn main() {
    // Define and store an anonymous function
    fn (x:i64 -- r:i64) { 2 * } -> double

    // Call it with 'call'
    5 double call print nl  // 10
}

The signature follows the same format as regular functions: (inputs -- outputs).

Inline usage

Anonymous functions can be used directly without storing them:

fn main() {
    // Define and call immediately
    5 fn (x:i64 -- r:i64) { 2 * } call print nl  // 10

    // Multiple parameters
    10 20 fn (a:i64 b:i64 -- r:i64) { + } call print nl  // 30
}

Side-effect functions

Functions that don't return values use an empty output signature:

fn main() {
    fn () { "Hello!" print nl } -> greet
    greet call  // Hello!

    // Or inline
    fn () { "Goodbye!" print nl } call  // Goodbye!
}

Reusing anonymous functions

Once stored, an anonymous function can be called multiple times:

fn main() {
    fn (x:i64 -- r:i64) { 2 * } -> double

    // Use in a loop
    1 6 1 for i {
        i double call print nl
    }
    // Output: 2 4 6 8 10
}

Control flow inside

Anonymous functions can contain conditionals and other control flow:

fn main() {
    fn (x:i64 -- r:i64) {
        dup 0 > if {
            10
        } else {
            0
        }
    } -> positive_to_ten

    5 positive_to_ten call print nl   // 10
    -3 positive_to_ten call print nl  // 0
}

Closures (variable capture)

Anonymous functions can capture variables from their enclosing scope, creating closures:

fn main() {
    10 -> multiplier

    // This closure captures 'multiplier' from the outer scope
    fn (x:i64 -- r:i64) { multiplier * } -> scale

    5 scale call print nl   // 50
    7 scale call print nl   // 70
}

Capture by reference

Variables are captured by reference. Changes to the original variable are visible to the closure:

fn main() {
    10 -> x

    fn ( -- r:i64) { x } -> get_x

    get_x call print nl  // 10

    99 -> x  // Change the original variable
    get_x call print nl  // 99 (sees the change)
}

Multiple captures

Closures can capture multiple variables:

fn main() {
    10 -> a
    20 -> b
    30 -> c

    fn ( -- r:i64) { a b add c add } -> sum_all

    sum_all call print nl  // 60
}

Closures in loops

Closures created inside loops capture the current value at each iteration:

fn main() {
    0 5 1 for i {
        i -> val
        fn ( -- r:i64) { val } -> c
        c call print nl
    }
    // Output: 0 1 2 3 4
}

Nested closures

Closures can be nested, with inner closures capturing variables from outer closures:

fn main() {
    10 -> x

    fn ( -- r:i64) {
        x -> y
        fn ( -- r:i64) { y } -> inner
        inner call
    } -> outer

    outer call print nl  // 10
}

Returning closures

Functions can return closures that capture their local variables:

fn make_adder(n:i64 -- adder:ptr) {
    -> amount  // Store parameter in local variable
    fn (x:i64 -- r:i64) { amount add }
}

fn main() {
    5 make_adder -> add5
    10 make_adder -> add10

    100 add5 call print nl   // 105
    100 add10 call print nl  // 110
}

Calling named functions

Anonymous functions can call regular named functions:

fn helper(a:i64 -- r:i64) {
    10 +
}

fn main() {
    fn (a:i64 -- r:i64) { helper 2 * } -> process
    5 process call print nl  // 30 (5+10=15, 15*2=30)
}

Comparison with function pointers

Anonymous functions and function pointers both use call:

// Named function with pointer
fn double(x:i64 -- r:i64) { 2 * }

fn main() {
    // Function pointer to named function
    &double -> fp1
    5 fp1 call print nl  // 10

    // Anonymous function
    fn (x:i64 -- r:i64) { 2 * } -> fp2
    5 fp2 call print nl  // 10
}

The difference is that anonymous functions are defined inline, while function pointers reference separately defined functions.

What's next?

Learn about Higher-Order Functions for passing functions as arguments.