## Pattern Matching

### Matching on Enums

Flix supports pattern matching on algebraic data types.

For example, if we have an algebraic data type that models shapes:

``````enum Shape {
case Circle(Int32)
case Square(Int32)
case Rectangle(Int32, Int32)
}
``````

Then we can write a function to compute the area of a `Shape` using pattern matching:

``````def area(s: Shape): Int32 = match s {
case Shape.Circle(r)       => 3 * (r * r)
case Shape.Square(w)       => w * w
case Shape.Rectangle(h, w) => h * w
}
``````

### Matching on Records

The above also works for record types; however, the syntax is slightly different. Let us rewrite the `Shape` type from before, this time using records.

``````enum Shape {
case Circle({ radius = Int32 })
case Square({ width = Int32 })
case Rectangle({ height = Int32, width = Int32 })
}

def area(s: Shape): Int32 = match s {
case Shape.Circle({ radius })           => 3 * (radius * radius)
case Shape.Square({ width })            => width * width
case Shape.Rectangle({ height, width }) => height * width
}
``````

In the example above, we implicitly require that each pattern has exactly the specified labels. No more, no less. However, in general, the syntax for record patterns is similar to their types. Thus, we can match on a record that has at least one specific label.

``````def f(r: { height = Int32 | a }): Int32 = match r {
case { height | _ } => height
// The extension has a wildcard pattern since it is unused
}
``````

Note, however, that the pattern also implies a type, thus the following example will not work.

``````def badTypes(r: { height = Int32 | a }): Int32 = match r {
case { height } => height
}
``````

Additionally, all cases must have the same type, so this will also not work:

``````match ??? {
case { height | _ } => height
case { height }     => height
}
``````

This may be a contrived example, but it demonstrates a common pitfall, which is easily fixed.

This is because the first case is a polymorphic record with a defined `height`-label, whereas the second case matches on a closed record that only has the `height`-label defined.

Additionally, the `{ label }` pattern is actually syntactic sugar for `{ label = pattern }`. Thus, if you are dealing with multiple records, then it may be necessary to use different patterns.

``````def shadowing(r1: { height = Int32 | a }, r2: { height = Int32 | b }): Int32 =
match (r1, r2) {
case ({ height | _ }, { height | _ }) => height + height
// This does not work because `height = height` is defined twice
}
``````

However, renaming the variables makes the program type check.

``````def renaming(r1: { height = Int32 | a }, r2: { height = Int32 | b }): Int32 =
match (r1, r2) {
case ({ height = h1 | _ }, { height = h2 | _ }) => h1 + h2
}
``````

To summarize, here are a few examples of record patterns:

• `{ }` - the empty record
• `{ radius = r }` - a record containg only the label `radius` where the value is bound to `r` in the scope
• `{ radius }` - a record containing only the label `radius` (this is actually syntactic sugar for `{ radius = radius }`)
• `{ radius | _ }` - a record containg at least the label `radius`
• `{ radius | r }` - a record containg at least the label `radius` where the rest of the record is bound to `r`

### Let Pattern Match

In addition to the pattern `match` construct, a let-binding can be used to destruct a value. For example:

``````let (x, y, z) = (1, 2, 3)
``````

Binds the variables `x`, `y`, and `z` to the values `1`, `2`, and `3`, respectively.

Any exhaustive pattern may be used in a let-binding. For example:

``````let (x, Foo(y, z)) = (1, Foo(2, 3))
``````

is legal provided that the `Foo` constructor belongs to a type where it is the only constructor.

The following let-bindings are illegal because they are not exhaustive:

``````let (1, 2, z) = ...
let Some(x) = ...
``````

The Flix compiler will reject such non-exhaustive patterns.

Let-pattern-matches work well with records, as they allow you to destructure a record and only use the labels you are interested in:

``````let { height | _ } = r;
height + height
``````

### Match Lambdas

Pattern matches can also be used with lambda expressions. For example:

``````List.map(match (x, y) -> x + y, (1, 1) :: (2, 2) :: Nil)
``````

is equivalent to:

``````List.map(w -> match w { case (x, y) => x + y }, (1, 1) :: (2, 2) :: Nil)
``````

As for let-bindings, such pattern matches must be exhaustive.

Note the difference between the two lambda expressions:

``````let f = (x, y, z) -> x + y + z + 42i32
let g = match (x, y, z) -> x + y + z + 42i32
``````

Here `f` is a function that expects three `Int32` arguments, whereas `g` is a function that expects one three tuple `(Int32, Int32, Int32)` argument.