Functions

Aside from built-in methods and functions, RCL supports user-defined functions.

let add = (x, y) => x + y;
// Evaluates to 42.
add(22, 20)

Functions are first-class: they are values that can be assigned to variables and passed to other functions. Functions are anonymous: the name you use to call them is not an inherent property of the function, but of the variable that it is assigned to. Functions are closures: the function body can reference variables defined outside of the body. Such functions are sometimes called lambda functions or lambdas in other languages.

Defining functions

A => arrow creates a function, with the arguments on the left and the body on the right.

let sub = (x, y) => x - y;
// Evaluates to 42.
sub(50, 8)

A trailing comma in the argument list is optional.

let sub = (
  x,
  y,
) => x - y;

When a function takes a single argument, the parentheses may be omitted.

let double_input = x => x * 2;

Closures

A function can capture variables defined outside the function body. The names remain bound to the values they had when the function was defined. If a later let-binding shadows an earlier one, this does not affect the function.

let x = 42;
let get_x = () => x;
let x = 0;
// Evaluates to 42, not to 0, because x was bound to 42 when get_x was defined.
get_x()

Variables in RCL bind names to immutable values, not to mutable memory locations. This means that in a loop, functions capture the value that a variable has in that iteration of the loop.

let fs = [for k in [1, 2, 3]: x => x * k];
// Evaluates to [10, 20, 30].
[for f in fs: f(10)]

First-class functions

Functions are values and can be passed to functions:

let apply_twice = (f, x) => f(f(x));
// Evaluates to 256 = (4 * 4) * (4 * 4);
apply_twice(x => x * x, 4)

This is useful with built-in methods such as List.group_by.

let replicants = [
  { activation_year = 2016, name = "Pris Stratton" },
  { activation_year = 2016, name = "Roy Batty" },
  { activation_year = 2017, name = "Leon Kowalski" },
];
replicants.group_by(r => r.activation_year)
// Evaluates to:
{
  2016: [
    { activation_year = 2016, name = "Pris Stratton" },
    { activation_year = 2016, name = "Roy Batty" },
  ],
  2017: [
    { activation_year = 2017, name = "Leon Kowalski" },
  ],
}