erg/doc/EN/syntax/26_pattern_matching.md
2022-08-30 21:58:09 +09:00

4 KiB

Pattern matching, Irrefutability

badge

Patterns Available in Erg

Variable Pattern

# basic assignment
i = 1
# with type
i: Int = 1
# with anonymous type
i: {1, 2, 3} = 2
# function
fn x = x + 1
# equals
fn x: Add(Int) = x + 1
# (anonymous) function
fn = x -> x + 1
fn: Int -> Int = x -> x + 1
# higher-order type
a: [Int; 4] = [0, 1, 2, 3]
# or
a: Array Int, 4 = [0, 1, 2, 3] # or

Literal Pattern

# if `i` cannot be determined to be 1 at compile time, TypeError occurs.
# short hand of `_: {1} = i`
1 = i
# simple pattern matching
match x:
    1 -> "1"
    2 -> "2"
    _ -> "other"
# fibonacci function
fib 0 = 0
fib 1 = 1
fib n: Nat = fib n-1 + fib n-2

Constant Pattern

cond = False
match! cond:
    True => print!
    _ => print! "cond is False"

PI = 3.141592653589793
E = 2.718281828459045
num = PI
name = match num:
    PI -> "pi"
    E -> "e"
    _ -> "unnamed"

Refinement Pattern

Array(T, N: {N | N >= 3})
# == ==
Array(T, N | N >= 3)

f M, N | M >= 0, N >= 1 = ...
f(1, 0) # TypeError: N (2nd parameter) must be 1 or more

Discard (Wildcard) Pattern

_ = 1
_: Int = 1
zero _ = 0
right(_, r) = r

Varargs Patterns

Used in combination with the tuple/array/record pattern described below.

[i, . .j] = [1, 2, 3, 4]
assert j == [2, 3, 4].
first|T|(fst: T, ...rest: T) = fst
assert first(1, 2, 3) == 1

Tuple Pattern

(i, j) = (1, 2)
((k, l), _) = ((1, 2), (3, 4))
# () can be omitted if not nested (1, 2 are treated as (1, 2))
m, n = 1, 2

f(x, y) = ...

Array Pattern

[i, j] = [1, 2]
[[k, l], _] = [[1, 2], [3, 4]]

length [] = 0
length [_, . .rest] = 1 + length rest

Record Pattern

record = {i = 1; j = 2; k = 3}
{j; ...} = record # i, k will be freed

{sin; cos; tan; ...} = import "math"
{*} = import "math" # import all

person = {name = "John Smith"; age = 20}
age = match person:
    {name = "Alice"; _} -> 7
    {_; age} -> age

f {x: Int; y: Int} = ...

Data Class Pattern

Point = Inherit {x = Int; y = Int}
p = Point.{x = 1; y = 2}
Point.{x; y} = p

Nil T = Class Impl: Phantom T
Cons T = Inherit {head = T; rest = List T}
List T = Enum Nil(T), Cons(T)
List T.
    first self =
        match self:
            Cons.{head; ...} -> x
            _ -> ...
    second self =
        match self:
            Cons.{rest=Cons.{head; ...} ; ...} -> head
            _ -> ...

Enumeration Pattern

  • actually just an enumerated type
match x:
    i: {1, 2} -> "one or two: {i}"
    _ -> "other"

Range Pattern

  • actually just an interval type
# 0 < i < 1
i: 0<... <1 = 0.5
# 1 < j <= 2
_: {[I, J] | I, J: 1<. .2} = [1, 2]
# 1 <= i <= 5
match i
    i: 1..5 -> ...

Non-patterns and Non-patternable Items

A pattern is something that can be uniquely specified. In this respect, pattern matching differs from ordinary conditional branching.

The specification of a condition is not unique. For example, to determine whether the number n is even, the orthodox way is n % 2 == 0, but it can also be written as (n / 2).round() == n / 2. The non-unique form is non-trivial, whether it works correctly or is equivalent to another condition.

Set

There is no pattern for sets. There is no pattern for sets because there is no way to retrieve elements uniquely. They can be retrieved with an iterator, but the order is not guaranteed.

Previous | Next