Functions

Functions in Parsley are first-class values created with fn. They are always anonymous — naming happens through let binding. The body is a block, and the last expression is the implicit return value.

Basic Syntax

let double = fn(x) { x * 2 }
let add = fn(a, b) { a + b }
let hello = fn() { "hello" }
let thunk = fn { 99 }           // parens optional when no parameters

double(5)                        // 10
add(3, 4)                        // 7
thunk()                          // 99

Return Values

The last expression in a block is the return value — no return needed:

let double = fn(x) {
    x * 2                        // automatically returned
}

When to Use return

In most Parsley code, return is redundant. The language is expression-oriented: functions, if/else, and for all produce values naturally. Prefer implicit returns for cleaner code.

Don't reach for return when:

// ❌ Unnecessary return
let double = fn(x) { return x * 2 }

// ✅ Implicit return
let double = fn(x) { x * 2 }

// ❌ Return for guards
let process = fn(x) {
    if (!x) { return null }
    x.value
}

// ✅ check...else for guards
let process = fn(x) {
    check x else null
    x.value
}

Do use return for early exit from inside loops — this is its primary purpose:

let contains = fn(arr, value) {
    for (item in arr) {
        if (item == value) {
            return true          // exits the function, not just the loop
        }
    }
    false
}

Note that stop exits the loop but continues the function; return exits the function entirely. When you need to bail out of a loop and return from the enclosing function, return is the right tool.

Parameter Destructuring

Function parameters can destructure dictionaries and arrays directly:

// Dictionary destructuring
let greet = fn({name, age}) {
    name + " is " + age
}
greet({name: "Alice", age: 30})  // "Alice is 30"

// Array destructuring with rest
let process = fn([first, ...rest]) {
    {first: first, rest: rest}
}
process([10, 20, 30])            // {first: 10, rest: [20, 30]}

This is the standard pattern for components — a single dict parameter with named fields:

let Card = fn({title, body}) {
    <div class="card">
        <h2>title</h2>
        <p>body</p>
    </div>
}
<Card title="Hello" body="World"/>

When a component tag has children, they arrive as contents:

let Wrap = fn({contents}) {
    <div class="wrap">contents</div>
}
<Wrap><p>"inner"</p></Wrap>

Closures

Functions capture their enclosing environment by reference:

let make_counter = fn() {
    let count = 0
    fn() {
        count = count + 1
        count
    }
}
let c = make_counter()
c()                              // 1
c()                              // 2
c()                              // 3

this Binding

When a function is stored as a dictionary value and called as a method, this is automatically bound to the dictionary:

let user = {
    name: "Alice",
    greet: fn() { "Hello, " + this.name }
}
user.greet()                     // "Hello, Alice"

this is only available inside methods called via dot notation. Calling the function directly (not through the dict) won't bind this.

First-Class Usage

Functions are values — pass them to methods, store them in arrays, return them from other functions:

[1, 2, 3].map(fn(x) { x * 10 })          // [10, 20, 30]
[1, 2, 3, 4, 5].filter(fn(x) { x > 3 })  // [4, 5]
[1, 2, 3, 4, 5].reduce(fn(acc, x) { acc + x }, 0)  // 15

Immediately Invoked

fn() { 42 }()                    // 42
fn(x) { x * 2 }(5)              // 10

Argument Handling

Parsley does not support default parameter values. Missing arguments leave the parameter unbound (using it will cause an "identifier not found" error). Extra arguments are silently ignored.

let f = fn(a, b) { a }
f(1, 2, 3)                      // 1  (third arg ignored)
f(1)                             // 1  (b unbound but unused, so no error)

⚠️ Built-in functions and methods enforce arity strictly and will error on wrong argument counts. User-defined functions do not — they silently accept any number of arguments.

Key Differences from Other Languages

See Also