Functions
mq supports named functions defined with def, anonymous functions defined with fn, and the -> arrow shorthand.
Named Functions
Named functions are defined with def and can be called by name throughout the program.
Syntax
A function body can be terminated with ; or end:
def function_name(parameters):
program;
def function_name(parameters):
program
end
Examples
# Using semicolon terminator
def double(x):
mul(x, 2);
# Using end terminator
def double(x):
mul(x, 2)
end
# Function with conditional logic
def is_positive(x):
gt(x, 0);
# Composition of functions
def add_then_double(x, y):
add(x, y) | double(self);
Default Parameters
def function_name(param1, param2=default_value):
program;
# Function with default parameter
def greet(name, greeting="Hello"):
greeting + " " + name;
# Using end terminator
def greet(name, greeting="Hello"):
greeting + " " + name
end
# Using default value
greet("Alice")
# Output: "Hello Alice"
# Overriding default value
greet("Bob", "Hi")
# Output: "Hi Bob"
# Default value can be an expression
def add_with_offset(x, offset=10 + 5):
x + offset;
add_with_offset(20)
# Output: 35
Anonymous Functions
Anonymous functions (lambda expressions) are defined with fn or the -> shorthand, and can be passed as arguments, assigned to variables, or used inline.
Syntax
A function body can be terminated with ; or end:
fn(parameters): program;
fn(parameters): program end
The -> syntax is a shorthand alias for fn:
->(parameters): program;
->(parameters): program end
Examples
# Basic anonymous function
nodes | map(fn(x): add(x, "1");)
# Using end terminator
nodes | map(fn(x): add(x, "1") end)
# Using arrow syntax
nodes | map(->(x): add(x, "1");)
# As a callback
nodes | .[] | sort_by(fn(x): to_text(x);)
# Assigned to a variable
let multiply = fn(x, factor=2): x * factor;
Default Parameters
fn(param1, param2=default_value): program;
# Anonymous function with default parameter
let multiply = fn(x, factor=2): x * factor;
# Using end terminator
let multiply = fn(x, factor=2): x * factor end
# Using default value
multiply(10)
# Multiplies by 2 (default factor)
# Overriding default value
multiply(10, 3)
# Multiplies by 3
# Using in callbacks
[1, 2] | map(fn(x, prefix="Item: "): prefix + to_text(x);)
Rules
- Parameters with default values must come after parameters without default values
- Default values are evaluated when the function is called, not when it is defined
- Default values can be any valid expression
Parenthesis-Free Calls
Functions with 0 or 1 required parameters can be called without parentheses when used as pipeline steps.
- A 0-argument function invoked without
()is called with no explicit arguments. - A 1-argument function invoked without
()receives the current pipeline value as its implicit argument.
This only applies in pipeline position (as a pipeline step). When a function is passed as a value to another function (e.g., map(arr, f)), no auto-call occurs and the function reference is preserved.
# 0-arg function: called without parentheses
def greet(): "Hello!";
| greet # equivalent to greet()
# Output: "Hello!"
# 1-arg function: current value is passed implicitly
def double(x): x * 2;
| 5 | double # equivalent to 5 | double(5), i.e., double(5)
# Output: 10
# Builtin functions also support paren-free calls
"hello world" | upcase # equivalent to upcase("hello world")
# Output: "HELLO WORLD"
[1, None, 2] | compact | len # chained paren-free calls
# Output: 2
# Function references are preserved when passed as arguments
map(["a", "b"], upcase) # upcase is NOT auto-called here; it's passed as a callback
# Output: ["A", "B"]