Skip to content

Functions

In Calibre, functions are values.

That means you can store them in variables, pass them around, and call them later just like other values.

Note that if you have function with multiple adjacent parameters having the same type that the comma between them can be removed and only one type annotation will be required.

const add := fn (a b : int) -> int => a + b;
let op := add;
print(op(2, 3));

Functions are also all anonymous. You create a function with fn, and if you want to reuse it, you bind it to a name.

let double := fn (x : int) -> int => x * 2;
print(double(10));

Function types are written with fn (...) -> ... ot fn -> ....

const add : fn (int, int) -> int = fn (a b : int) -> int => a + b;
// Note that the parameters brackets aren't required if there are no parameters
const add_2_5 : fn -> int = fn => add(2, 5);

This is useful when you want to describe the shape of a function value explicitly.

You can define functions inline wherever they are needed.

print((fn (x : int) -> int => x + 1)(9));

Calibre can often infer parameter types and return types when enough information is available.

Here, the function value is assigned to a binding with a known function type, so the parameter and return types can be inferred from that context.

const add : fn (int, int) -> int = fn (a, b) => a + b;

Return types can also be inferred from the function body when the result is clear.

const double := fn (x : int) => x * 2;

Both return and parameter types can also be inferred based on usage throughout the program.

Here, the types are being inferred based on how they’re used in the main function and the body of the function itself resulting in the parameter and return types all being floats

const multiply := fn(a b) => a * b;
const main := fn => print(multiply(10f, 12.5));

If you want to be explicit, you can still write both parameter and return types directly on the function.

const greet := fn (name : str) -> str => "Hello " & name;

Because functions are values, they work naturally with other features like list operations and generators.

let mapped := list:<int>[1, 2, 3].into_iter().map(fn (x : int) -> int => x * 10).collect();
print(mapped);