Skip to content

Functions

Use fn to declare a function with named parameters:

fn greet(name) {
echo "hello, $name"
}
greet("world") # hello, world

The return value is the last expression evaluated in the body:

fn double(x) {
x * 2
}
let result = double(5) # 10

Separate parameters with commas:

fn add(a, b) {
a + b
}
let sum = add(3, 4) # 7
fn clamp(value, lo, hi) {
if value < lo {
lo
} else if value > hi {
hi
} else {
value
}
}
let clamped = clamp(150, 0, 100) # 100

Functions are declared with let semantics. They live in the command namespace, separate from the variable namespace. You cannot reassign a function name.

Lambdas capture their declaration scope:

fn make_multiplier(factor) {
x => x * factor
}
let triple = make_multiplier(3)
[1, 2, 3, 4].map(triple) # [3, 6, 9, 12]

Functions integrate naturally with map, filter, and other chain methods:

fn is_source_file(name) {
name.endsWith(".d") || name.endsWith(".di")
}
fn format_entry(path) {
" -> $path"
}
`ls -R src/`.filter(x => is_source_file(x)).map(x => format_entry(x))

With reduce:

fn running_total(acc, x) {
acc + x.toNumber()
}
let total = `cat amounts.txt`.reduce(0, (acc, x) => running_total(acc, x))
(total)

A script that processes server logs and summarizes status codes:

fn extract_status(line) {
line.split(" ")[8]
}
fn is_error(status) {
status.startsWith("5") || status.startsWith("4")
}
let errors = `cat access.log`
.map(x => extract_status(x))
.filter(x => is_error(x))
.wordcount()
.take(10)
for entry in errors {
echo "status $(entry["word"]): $(entry["count"]) occurrences"
}

Functions can call themselves:

fn factorial(n) {
if n <= 1 {
1
} else {
n * factorial(n - 1)
}
}
let result = factorial(6) # 720
(result)

Be mindful of lash’s loop protection — recursive calls are not subject to the loop iteration limit, but deep recursion may exhaust the call stack.