Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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"]