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)
```