Skip to content

Pattern Matching

As filtrera is not proceedural, control-flow using classic if-statements doesn’t make much sense, and are not part of the language. Instead filtrera provides powerful pattern matching to cover any conditional control flow you might need.

Pattern matching is carried by two keywords:

is functions as an operator and matches the left hand side with the right hand pattern. The result is a boolean.

match is more powerful and allows you to create separate paths given a path. But before we get to that, let’s discuss what a pattern is.

A pattern is any type descriptor. Since types can be literal, a pattern can also be a value. Perhaps some examples can make it more clear:

// Results in true as 'hello' is a text
from 'hello' is text
// Results in true as 'hello' is exactly 'hello'
from 'hello' is 'hello'
// Results in true as 'hello' is not 'world'
from 'hello' is not 'world'
// Results in false as 'hello' is not a number
from 'hello' is number
// Results in true as 'hello' is not a number
from 'hello' is not number

match

The match keyword is especially powerful, as it allows a vastly different execution paths based on a pattern. In simple terms, match takes an input value and matches it against a list of filters. The first filter to match will be evaluated:

param input: value
from input match
text |> 'input is a text'
number |> 'input is a number'
|> 'input was something else'

Note that a filter with no input type constraint matches anything.

Just as with filters, input type can be a tuple that deconstructs the values:

param input: value = (a: 1, b: 2)
from input match
(value1: number, value2: number) |> '{value1} and {value2}'
|> 'Unsupported type'

As filters also allows conditions, we can provide a predicate to do even more advanced matching.

Here’s an example:

param valueA = 5
param valueB = 3
from val match
when valueA > valueB |> valueA - valueB
when valueA < valueB |> valueB - valueA
|> 0

Inferring symbol types

When pattern matching is used against a symbol, filtrera can assume the type of that symbol moving forward.

In the below example, the function’s parameter can be any type. But we can still multiple the value if it’s a number. Multiply operator would not be allowed on a non-number type, but in this case it’s allowed as val must be a number in order to enter the filter.

let myFunc val => val match
number |> val * 2
value |> '{val}'
nothing |> 'nothing'