Closures & Functions
RQL scripts can define functions two ways: anonymous closures bound to variables (let $double = ($x) { $x * 2 }) and named functions declared with udf. Both turn a repeated computation into one definition, both live only for the request that defines them, and they differ in exactly one practical way: where they can be called.
Define a closure, call it
A closure is a parenthesized parameter list followed by a block, assigned to a variable with let. Calling the variable runs the body; when the call is the final statement of a request, its result comes back as a one-value frame:
Closures capture their scope
The body can reference variables from the enclosing scope - that is what makes it a closure rather than just a function. Here $base is not a parameter; it is captured:
Parameters win over captures of the same name. Inside the body, $x is the argument, not the outer variable:
Bodies are blocks
A closure body is a full block: it can declare its own variables, and its last expression is the return value:
Closures compose - a closure can call another closure it captured:
Using closures in queries
To feed a closure's result into a pipeline, bind it with let and use the variable:
What does not work is calling the closure variable inline inside a pipeline expression - map and filter do not resolve $f(4) as a callable:
Named functions with udf
When the whole point is to call the function from inside a pipeline, declare it with udf instead. A named udf is callable anywhere a built-in function is:
udf bodies use explicit return, and return exits immediately - combined with if that gives guard-clause style logic:
A udf returning a boolean works as a reusable predicate:
And a udf can wrap statements, not just expressions - including writes. This is the pattern for "do this parameterized thing N times" inside one request:
One request, then gone
Closures and udfs are script constructs, not schema objects. They exist from their definition to the end of the request - the next request starts clean:
create procedure, stored in a namespace, and invoked with call. Reach for closures and udfs to structure the logic inside one script; reach for procedures to give that logic a permanent name in the database.