Function definitions in Rax have the following form:

output_type <- input_type: function_name <- { // Function body out := some_transformation_of(in); };

The first thing to note is that Rax functions have
only *one* parameter and one result. The parameter
and the result, however, can be of complex type, such as tuple or
set. Therefore, one can pass an arbitrary number of parameters and
return an arbitrary number of results by grouping them into a tuple.

Within the function body, there are two special variables
available: `in`

that contains the value of the
parameter passed to the function and `out`

to which
the result should be assigned within the function body. Since most
functions have a tuple as their input type, and many also as their
output type, the with-clause is particularly handy
when writing functions. Below an example function:

[&:x, &:y]: Point; & <- [\Point: p1, \Point: p2]: cartesianDistance <- { in.{ out := sqrt:((p2.x - p1.x)**2 + (p2.y - p1.y)**2); }; out := out :\ 1e-4; // Floor for nice output. };

An invocation of a function looks as you would expect:

\Point: p1 := [1.0, 2.5]; \Point: p2 := [2.5, 1.0]; `print cartesianDistance(p1,p2); // Output: 2.1213

**Recursion. **
Rax allows the functions to be recursive. As an example, a very
inefficient implementation of a famous series:

#<-#: FibonacciNum <- { out := in ? <= 0 : 0 ? == 1 : 1 ? : FibonacciNum(in - 1) + FibonacciNum(in - 2); }; `print FibonacciNum(9); // Output: 34

Note that number in Rax are limited to 64 bits, so the 92^{nd}
Fibonacci number is the largest number that can be generated this
way.

**Nested functions. **
Unlike C, Rax supports * nested
functions*, i.e., functions that are lexically
encapsulated within other functions. The

{[#:id, &:pr_pension]} <- {[#:id, &:age, &:cur_income]}: predict <- { &: secret_coefficient := 0.6784; & <- [&:age, &:income]: secret_formula <- { in.{ out := secret_coefficient * age * income; } } out := project[.id, secret_formula(.age, .cur_income)] .in; }; {[#:id, &:age, &:income]}: incomes := ... {[#:id, &:pension]}: predicted_pensions := predict(incomes);

In this example, we defined a function `predict`

that predicts the pensions of a group of
people. Function `predict`

defines a nested
function `secret_formula`

, which computes the
predicted pension based on age, current income, and a secret
coefficient. Note that `secret_coefficient`

is
defined outside the nested function. In Rax, unlike some other
functional languages, functions can access non-local variables.

**Higher-order functions. **
Functions in Rax are *first-class citizens*, which
means that they can be passed as arguments to other functions,
returned as values from other functions and assigned to
variables. This allows to define *higher-order
functions*, i.e., functions that take other functions as
parameters and/or return functions as parameters. An example of an
higher-order function is shown below:

#: C, T, K; // Use numbers for all. \C <- \T: Cipher; // Cipher has built-in key. \C <- [\K: key, \T: txt]: Coder; // One step en/decoder. \Coder: Encode <- { out := in.txt + in.key; }; \Coder: Decode <- { out := in.txt - in.key; }; // mkCipher: build Cipher from coder and key. \Cipher <- [\Coder: coder, \K: key]: mkCipher <- { in.{ out <- { out := coder(key, in); // Apply key to in. }; }; }; \Cipher: Single := mkCipher(Encode, 6); `print Single(3); // Output: 9

In the example above, five (uninitialized) variables are defined. Throughout
the rest of the code snippet, these variables are not used to store values but to be
used in conjunction with the *type-of* operator:
`\`

. A variable used like this is called a *type
holder* for obvious reasons.
Of these five type holders, two are functions: `Coder`

and
`Cipher`

. The first has the type `# <- #`

indicating that it is a function that converts a number into a number. The second
function has a slightly more complex type: it converts a `\K`

(a key,
in this case a number) and a `\T`

(a text, in this case also a number)
into a `\C`

(a ciphertext, number).
Traditionally, higher order functions start with `mk`

. In the above
example the higher order function: `mkCipher`

, makes a
`\Cipher`

, i.e., a function. Its input arguments include a
`\Coder`

, i.e., also a function.
A slightly more complex example is shown below:

// mkTDEA: TDEA from encoder, decoder and three keys. \Cipher <- [\Coder: E, \Coder: D, \K: k * 3]: mkTDEA <- { in.{ out <- { out := E(k#1, D(k#2, E(k#3, in))); }; }; }; \Cipher: Keying'1 := mkTDEA(Encode, Decode, 6, 8, 3); \Cipher: Keying'2 := mkTDEA(Encode, Decode, 6, 8, 6); \Cipher: Keying'3 := mkTDEA(Encode, Decode, 6, 6, 6); `print Keying'1(3); // Output: 4 `print Keying'2(3); // Output: 7 `print Keying'3(3); // Output: 9

The above higher-order function, `mkTDEA`

, builds a
`\Cipher`

function from a set of `\Coder`

functions
and the three keys. Note that by replacing the type holders with more suitable
ones, this code actually could be used to implement a usable version of the Triple Data
Encryption Algorithm. The `Encoder`

and `Decoder`

functions would need some changes too.

**Closures. **
Since Rax functions are first-class citizens and can access non-local
variables, support
for * closures* is
necessary. A

`derive`

function:
& <- &: Func; \Func <- \Func: derive <- { &: dx := 1e-8; \Func: f := in; out <- { &:y := f(in); &:dy := f(in + dx) - y; out := dy/dx; out := out :\ 1e-4; // Floor for nice output. }; }; \Func: my_func <- { out := 2 * in**2 + 3 * in - 4; }; \Func: my_func' := derive(my_func); `print my_func(0); // Output: -4 `print my_func'(0); // Output: 3

In this example, `dx`

is not a function argument,
but a secret variable declared within the body of
function `derive`

. However, `my_func'`

can still access it, even though it was called from
outside `dx`

's scope.