Functions & Closures
Weave has first-class functions, closures, and lambdas. Functions can be passed as arguments, returned from other functions, and stored in containers.
Defining Functions
fn add(a, b) {
a + b # last expression is implicitly returned
}
result = add(2, 3) # 5Default Parameters
Required parameters must come first:
fn greet(name, greeting: "Hello") {
greeting + ", " + name + "!"
}
greet("Alice") # "Hello, Alice!"
greet("Bob", "Hi") # "Hi, Bob!"
greet(greeting: "Hey", name: "Carol") # "Hey, Carol!"Named Arguments
All arguments can be passed by name using the same key: value syntax as containers:
fn div(a, b) { a / b }
div(b: 3, a: 2) # 0.6666...Early Return
fn find_first(items, target) {
i = 0
while i < items.len {
if items[i] == target { return i }
i += 1
}
false # this lets caller run "if find_first(...)"
}Lambdas
Lambdas are anonymous functions declared with ^:
double = ^(x) { x * 2 }
double(5) # 10
# Multi-line
process = ^(x) {
x = x + 1
x * 2
}
# Most commonly used inline with pipelines
[1, 2, 3] *> ^(x) { x * 2 } # [2, 4, 6]Lambdas are scoped to their declaring block:
fn outer(a, b) {
add = ^(a, b) { a + b }
add(a + 1, b + 1)
}
# add is not accessible hereVariadic Arguments
The *args syntax collects remaining arguments into a container:
fn add(a, b) { a + b }
fn partial(func, arg1) {
^(*args) { func(arg1, *args) }
}
add_5 = partial(add, 5)
add_5(10) # 15Closures
Functions capture variables from their enclosing scope. The captured values persist even after the enclosing function returns:
fn make_adder(n) {
a = 1
^(x) { x + n + a } # captures n and a
}
add_6 = make_adder(5)
add_6(10) # 16Factory Functions
Closures are the idiomatic way to build configurable functions:
fn make_multiplier(factor) {
^(x) { x * factor }
}
fn make_filter(predicate) {
^(items) {
result = []
items *> ^(item) {
if predicate(item) { result << item }
}
result
}
}
triple = make_multiplier(3)
filter_positive = make_filter(^(x) { x > 0 })
[1, 2, 3] *> triple # [3, 6, 9]
[-2, -1, 0, 1, 2] |> filter_positive # [1, 2]Partial Application
Create specialized functions by pre-filling arguments:
fn partial(func, arg1) {
^(*args) { func(arg1, *args) }
}
fn multiply(factor, value) { value * factor }
fn add(amount, value) { value + amount }
triple = partial(multiply, 3)
add_100 = partial(add, 100)
# Works naturally in pipelines
[1, 2, 3] *> triple *> add_100 # [103, 106, 109]Configurable Pipeline Components
fn column_extractor(column_name) {
^(row) { row[column_name] }
}
fn sum(v, acc: 0) { acc + v }
get_amount = column_extractor(:amount)
get_quantity = column_extractor(:quantity)
sales = read("sales.csv", :csv)
total_amount = sales *> get_amount &> sum
total_items = sales *> get_quantity &> sum