Docs / Function

# Function

Cheat sheet for the full function syntax at the end

Can you believe we haven't covered function until now?

Functions are declared with an arrow and return the expression.

```RE```let greet = (name) => "Hello " ++ name;
``````

This declares a function and assigns to it the name `greet`, which you can call like so:

```RE```greet("world!"); /* "Hello world!" */
``````

Multi-arguments functions have arguments separated by comma:

```RE```let add = (x, y, z) => x + y + z;
add(1, 2, 3); /* 6 */
``````

For longer functions, you'd surround the body with a block:

```RE```let greetMore = (name) => {
let part1 = "Hello";
part1 ++ " " ++ name
};
``````

## No Argument

A function always takes an argument; but sometimes, we'd use it for e.g. side-effects, and don't have anything to pass to it. In other languages, we'd conceptually pass "no argument". In Reason, every function takes an argument; here we'd conventionally pass it the value `()`, called "unit".

```RE```/* receive & destructure the unit argument */
let logSomething = () => {
print_endline("hello");
print_endline("world")
};

/* call the function with the value of type unit */
logSomething();
``````

`()` is a totally normal value, the single possible value in `unit`. Reason gave it a special syntax out of convenience.

## Labeled Arguments

Multi-arguments functions, especially those whose arguments are of the same type, can be confusing to call.

```RE```let addCoordinates = (x, y) => {
/* use x and y here */
};
/* ... */
addCoordinates(5, 6); /* which is x, which is y? */
``````

In OCaml/Reason, you can attach labels to an argument by prefixing the name with the `~` symbol:

```RE```let addCoordinates = (~x, ~y) => {
/* use x and y here */
};
/* ... */
``````

Since we have currying (more on that below), we can provide the arguments in any order:

```RE```addCoordinates(~y=6, ~x=5);
``````

The `~x` part in the declaration means the function accepts an argument labeled `x` and can refer to it in the function body by the same name. You can also refer to the arguments inside the function body by a different name for conciseness:

```RE```let drawCircle = (~radius as r, ~color as c) => {
setColor(c);
startAt(r, r);
/* ... */
};

``````

As a matter of fact, `(~radius)` is just a shorthand (called punning) for `(~radius as radius)`.

Here's the syntax for typing the arguments:

```RE```let drawCircle = (~radius as r: int, ~color as c: string) => ...;
``````

### Currying

Reason functions can automatically be partially called:

```RE```let add = (x, y) => x + y;
``````

Actually, the above `add` is nothing but syntactic sugar for this:

```RE```let add = (x) => (y) => x + y;
``````

OCaml optimizes this to avoid the unnecessary function allocation (2 functions here, naively speaking) whenever it can! This way, we get

• Nice syntax

• No performance cost

## Optional Labeled Arguments

Labeled function arguments can be made optional during declaration. You can then omit them when calling the function.

```RE```/* radius can be omitted */
let drawCircle = (~color, ~radius=?, ()) => {
setColor(color);
| None => startAt(1, 1)
| Some(r_) => startAt(r_, r_)
}
};
``````

When given in this syntax, `radius` is wrapped in the standard library's `option` type, defaulting to `None`. If provided, it'll be wrapped with a `Some`. So `radius`'s type value is either `None` or `Some(int)` here.

Note: `None | Some(foo)` is a data structure type called variant, described earlier. This particular variant type is provided by the standard library. It's called `option`. Its definition: `type option('a) = None | Some('a)`.

Note the unit `()` at the end of `drawCircle`. Writing this particular function without the unit `()` would lead to the following problem. Because `radius` and `color` are both labeled, the function can be curried, and it can be applied out-of-order, it's unclear what the following means:

```RE```let whatIsThis = drawCircle(~color);
``````

Is `whatIsThis` a curried `drawCircle` function, waiting for the optional `radius` to be applied? Or did it finish applying because the `radius` is optional? To address this confusion, append a positional (aka non-labeled) argument to `drawCircle` (conventionally `()`), and OCaml will, as a rule of thumb, presume the optional labeled argument is omitted when the positional argument is provided.

Because we don't supply the unit OCaml knows we want to curry the function.

```RE```let curriedFunction = drawCircle(~color);
``````

Because we do supply the unit OCaml knows we deliberately omit the `radius` parameter, and the function is executed.

```RE```let circle = drawCircle(~color, ());
``````

### Signatures and Type Annotations

Functions with optional labeled arguments can be confusing when it comes to signature and type annotations. Indeed, the type of an optional labeled argument looks different depending on whether you're calling the function, or working inside the function body. Outside the function, a raw value is either passed in (`int`, for example), or left off entirely. Inside the function, the parameter is always there, but its value is an option (`option(int)`). This means that the type signature is different, depending on whether you're writing out the function type, or the parameter type annotation. The first being a raw value, and the second being an option.

If we get back to our previous example and both add a signature and type annotations to its argument, we get this:

```RE```let drawCircle: (~color: color, ~radius: int=?, unit) => unit =
(~color: color, ~radius: option(int)=?, ()) => {
setColor(color);
| None => startAt(1, 1)
| Some(r_) => startAt(r_, r_)
};
};
``````

The first line is the function's signature, we would define it like that in an interface file (cf. Signatures). The function's signature describes the types that the outside world interacts with, hence the type `int` for `radius` because it indeed expects an `int` when called.

In the second line, we annotate the arguments to help us remember the types of the arguments when we use them inside the function's body, here indeed `radius` will be an `option(int)` inside the function.

So if you happen to struggle when writing the signature of a function with optional labeled arguments, try to remember this!

### Explicitly Passed Optional

Sometimes, you might want to forward a value to a function without knowing whether the value is `None` or `Some(a)`. Naively, you'd do:

```RE```let result =
| None => drawCircle(~color, ())
| Some(r) => drawCircle(~color, ~radius=r, ())
};
``````

This quickly gets tedious. We provide a shortcut:

```RE```let result = drawCircle(~color, ~radius=?payloadRadius, ());
``````

This means "I understand `radius` is optional, and that when I pass it a value it needs to be an `int`, but I don't know whether the value I'm passing is `None` or `Some(val)`, so I'll pass you the whole `option` wrapper".

### Optional with Default Value

Optional labeled arguments can also be provided a default value. In this case, they aren't wrapped in an `option` type.

```RE```let drawCircle = (~radius=1, ~color, ()) => {
setColor(color);
};
``````

## Recursive Functions

By default, a value can't see a binding that points to it, but including the `rec` keyword in a `let` binding makes this possible. This allows functions to see and call themselves, giving us the power of recursion.

```RE```let rec neverTerminate = () => neverTerminate();
``````

In imperative languages, including JavaScript, recursive functions are rarely used. In Reason, recursive functions are common, and can typically replace an imperative loop.

A simple recursive function may look like this:

```RE```/**
* Recursively check every item on the list until one equals the `item`
* argument. If a match is found, return `true`, otherwise return `false`.
*/
let rec listHas = (list, item) =>
switch (list) {
| [] => false
| [a, ...rest] => a == item || listHas(rest, item)
};
``````

Using recursion with a `switch` statement is a powerful combination that can sometimes produce code simpler than a standard library function like `fold` or `reduce`. In fact, if you dig into the Reason standard library's source code, you'll see that its implementations of `fold` or `reduce` are actually just recursive functions and `switch` statements!

### Tail Recursion

The reason why recursive functions are avoided in many languages, such as JavaScript, is those languages don't support "tail call optimization." This means that each time the function recurses, the previous call to the function is held in memory, which can lead to a stack overflow.

When the recursion happens in the tail position (meaning that the recursive call is the last step performed in the function), this can be optimized in a way that is stack safe. Fortunately for us, the Reason compiler is able to detect and perform this optimization.

For example, if you take our `listHas` function and compile it to JavaScript, you'll see that it removes the tail-calls by compiling into a `while` loop! Reason gives us the best of both worlds.

For writing `for` or `while` loops instead of recursive functions, see: Imperative Loops.

### Mutually Recursive Functions

Mutually recursive functions start like a single recursive function using the `rec` keyword, and then are chained together with `and`:

```RE```let rec callSecond = () => callFirst()
and callFirst = () => callSecond();
``````

Note that there's no semicolon ending the first line and no `let` on the second line.

## Tips & Tricks

Cheat sheet for the function syntaxes:

### Declaration

```RE```/* anonymous function. Listed for completeness only */
(x) => (y) => 1;
/* sugar for the above */
(x, y) => 1;
/* assign to a name */
let add = (x, y) => 1;

/* labeled */
let add = (~first as x, ~second as y) => x + y;
/* with punning sugar */
let add = (~first, ~second) => first + second;

/* labeled with default value */
let add = (~first as x=1, ~second as y=2) => x + y;
/* with punning */
let add = (~first=1, ~second=2) => first + second;

/* optional */
let add = (~first as x=?, ~second as y=?) => switch (x) {...};
/* with punning */
let add = (~first=?, ~second=?) => switch (first) {...};
``````

#### With Type Annotation

```RE```/* anonymous function */
(x: int) => (y: int): int => 1;
/* sugar for the above */
(x: int, y: int): int => 1;
/* assign to a name */
let add = (x: int, y: int): int => 1;

/* labeled */
let add = (~first as x: int, ~second as y: int) : int => x + y;
/* with punning sugar */
let add = (~first: int, ~second: int) : int => first + second;

/* labeled with default value */
let add = (~first as x: int=1, ~second as y: int=2) : int => x + y;
/* with punning sugar */
let add = (~first: int=1, ~second: int=2) : int => first + second;

/* optional */
let add = (~first as x: option(int)=?, ~second as y: option(int)=?) : int => switch (x) {...};
/* with punning sugar */
/* note that the caller would pass an `int`, not `option int` */
/* Inside the function, `first` and `second` are `option int`. */
let add = (~first: option(int)=?, ~second: option(int)=?) : int => switch (first) {...};
``````

### Application

```RE```/* anonymous application. Listed for completeness only */
/* sugar for the above */

/* labeled */
/* with punning sugar */

/* application with default value. Same as normal application */

/* explicit optional application */
/* with punning */
``````

#### With Type Annotation

```RE```/* anonymous application */

/* labeled */
/* with punning sugar */

/* application with default value. Same as normal application */

/* explicit optional application */
/* with punning sugar */
``````

### Standalone Type Signature

```RE```/* first arg type, second arg type, return type */
type foo = int => int => int;
/* sugar for the above */
type foo = (int, int) => int;

/* labeled */
type foo = (~first: int, ~second: int) => int;

/* labeled */
type foo = (~first: int=?, ~second: int=?, unit) => int;
``````

#### In Interface Files

To annotate a function from the implementation file (`.re`):

```RE```let add: int => int => int;
/* sugar for the above */
let add: (int, int) => int;
``````

Same rules as the previous section, except replacing `type foo = bar` with `let add: bar`.

Don't confuse this with actually exporting a type in the interface file. `let add: bar` annotates an existing value `bar` from the implementation file. `type foo = bar` exports a type of the same shape from the implementation file.