functions
================================================================================

%% A `function` maps input values to output values. In Mech, functions are branch-based and support pattern matching, recursion, and kind annotations.

1. Syntax
-------------------------------------------------------------------------------

Functions are defined with a signature, one or more guards, and a trailing `.`.

```
name(arg1<kind1>, arg2<kind2>, ...) => <return-kind>
  ├ pattern-1 => expression-1
  ├ pattern-2 => expression-2
  └ pattern-n => expression-n.
```

A function call uses regular call syntax:

```mech:disabled
name(value1, value2)
```

The argument name can be added to the call for named arguments:

```
name(arg1: value1, arg2: value2)
```

2. Semantics
-------------------------------------------------------------------------------

- Branches are matched from top to bottom.
- The first matching branch is selected.
- Function bodies are expressions.
- Functions can call themselves recursively.
- Calls are expressions, so they can be nested in formulas and broadcast over vectors/matrices.

3. Defining Functions
-------------------------------------------------------------------------------

(3.1) Recursive Power

```mech:ex 3.1
power(x<u64>, n<u64>) => <u64>
  ├ (*, 0u64) => 1u64
  └ (x, n) => x * power(x, n - 1u64).

power(2u64, 8u64)
```

(3.2) Recursive Factorial

```mech:ex 3.2
factorial(n<u64>) => <u64>
  ├ 0u64 => 1u64
  └ n => n * factorial(n - 1u64).

factorial(10u64)
```

(3.3) Recursive Fibonacci

```mech:ex 3.3
fib(n<u64>) => <u64>
  ├ 0u64 => 0u64
  ├ 1u64 => 1u64
  └ n => fib(n - 1u64) + fib(n - 2u64).

fib(10u64)
```

4. Calling Functions
-------------------------------------------------------------------------------

Functions are nomally called with the following call syntax:

```
fxn-name(value1, value2, ...)
```

Some functions have named arguments, which allow arguments to be passed in any order. In this case, the call syntax is:

```
fxn-name(arg1: value1, arg2: value2, ...)
```

Function calls can also broadcast over vectors:

```
fib(n<u64>) => <u64>
  ├ 0u64 => 0u64
  ├ 1u64 => 1u64
  └ n => fib(n - 1u64) + fib(n - 2u64).

xs := 0u64..=10u64
fib(xs)
```