Pattern matching is a powerful tool that compares a value against a several patterns until it finds one that matches. These patterns can range from simple literal values to a complex assortment and combination of other patterns, most of which are covered below.

Perhaps most importantly, pattern Matches with are completeness
checked, so all possibilities for a given value must be covered.
For example, a match against an integer x with a single
pattern `0`

(the equivalent of if x = 0) is rejected
as it does not have a case for when x != 0.

# Patterns

Every match expression must match a value against a list of patterns that are to be matched in order of declaration. There are several basic types of patterns: type cast patterns, operator patterns, destructures, clauses. Additionally, each type of pattern can be used within other patterns.

## Type Cast Pattern

Type cast patterns are in the form `Type val`

and are matched
if val’s type is Type. This is how each possible value of a
tagged-union types is matched against. For example, the type
`Maybe 't`

is one of two values: `None`

or `Some 't`

. In pattern
matching syntax, this translates to:

```
//typeof t = Maybe i32
let t = Some 2
match t with
| None -> print "none :("
| Some val -> print val
```

## Operator Patterns

An operator pattern is, simply put, a pattern that uses a
binary or unary operator. The semantics of which differs
depending on the operator used. The `+`

operator for example,
can be used in a patern (eg. `x + 3`

) to match any value and
have the binding (`x`

in this case) bound to the value matched
minus 3, and if the given type overloads the `-`

operator then the
overload is used. The other arithmetic operators follow this pattern as well.

```
match 3 with
| x + 2 -> assert(x = 1)
match (55, 12) with
| (y - 3, 15) -> assertUnreachable()
| (z / 2, 12) -> assert (z = 55 * 2)
| _ -> assertUnreachable()
//Pattern matching cannot be used as an equations solver
//
//Error: use of unbound value x in binding expression of x
match 0 with
| 2*x*x + 6*x + 4 -> assertUnreachable()
```

A more useful operator for patterns is the range operator `..`

which can
be used to test if a value is in a given range.

```
match 103 with
| -9..9 -> "1 digit"
| -99..99 -> "2 digits"
| _ -> "> 2 digits"
```

The append operator can also be used to check if a value has a given prefix or suffix:

```
match "my string" with
| "my " ++ item -> "I have a " ++ item
| "your " ++ item -> "You have a " ++ item
| _ -> "Someone has something. Probably."
```

## Clauses

Adding a clause in a pattern causes the pattern to only be
matched when the clause is true. Clauses use the `where`

keyword and are always boolean expressions. A clause also
has access to the bindings from the pattern it acts upon.

```
match 5 with
| small where small < 3 -> "small!"
| big where big > 10 -> "big!"
| _ -> "moderate."
match (3, "four") with
| (x, "four") where x > 5 -> ...
| (3, s) where len s > 3 -> ...
| _ -> ...
```

Much of the time a clause can be replaced with an inline boolean expression.

```
match 5 with
| _ < 3 -> "small!"
| _ > 10 -> "big!"
| _ -> "moderate."
match (3, "four") with
| (x > 5, "four") -> ...
| (3, len s > 3) -> ...
| _ -> ...
```

In match expressions any unbound identifier is bound to a value
based on its position in the pattern. For example, `s`

above refers
to the second index of the tuple type `(i32, Str)`

, and thus is a
`Str`

type. `len`

is already bound to a function, so it is not
rebound. The explicit `where`

clause can help prevent the ambiguity
that arises if it is unclear if `len`

or `s`

are already bound.

## Multiple Patterns

`|`

can be placed between two patterns so that its
branch is matched if either of those patterns are true.
It is essentially the `or`

operator for patterns.

```
fun fib: u32 n =
match n with
| 0 | 1 -> 1
| _ -> fib (n-1) + fib (n-2)
```

# Return Value

A match expression shares much of the same semantics of an if expression in that the types of its branches must match and the value returned is the value of the matched branch.

```
assert (3 = match "hi" with
| "yo" -> 1
| "hi" -> 3
| _ -> 5)
```

# Creating New Patterns

All functions that take a single parameter and return either
a boolean or a `Maybe 't`

can be used in a pattern expression.

```
fun positive: i32 x =
x > 0
match 4 with
| positive x ->
//the value bound of a boolean-returning function
//is just the value being matched
assert (x=4)
"4 is positive!"
| _ -> "4 is not positive."
```

As seen above, in the case of a boolean-returning function, the
matched value is bound to the identifier following the function
name. If some other value should be bound instead, a function
returning a `Maybe`

type can be used instead. If the function
returns `Some val`

then the pattern will be matched and the identifier
will be bound to `val`

.

```
fun positive: i32 x =
if x > 0 then Some "${x} is positive!"
else None
match 4 with
| positive msg ->
assert (msg = "4 is positive!")
print msg
//If this pattern is matched, then positive returned None
| _ -> "4 is not positive."
```

If the function requires multiple arguments, the other arguments can be specified as constants. This is also how the binary logical operators function within patterns:

```
fun approxEq: f64 a b =
abs (a - b) < 0.0001
match 56.0 with
| approxEq x 34.2 -> "x = 34.2"
| approxEq x 56.0 -> "x = 56.0"
| x < 2 -> "x < 2"
| _ -> "x = ?"
```