Pattern Matching on Lists

All the ways to pattern match on lists:

when input is
    [] -> EmptyList

    [_, ..] -> NonEmptyList

    ["Hi", ..] -> StartsWithHi

    [.., 42] -> EndsWith42

    [Foo, Bar, ..] -> StartsWithFooBar

    [Foo, Bar, Baz("Hi")] -> FooBarBazStr

    [Foo, Count(num), ..] if num > 0 -> FooCountIf

    [head, .. as tail] -> HeadAndTail(head, tail)

    _ -> Other

Note: this specific snippet would not typecheck because it uses lists of different types. This is just meant to be a compact overview. See the code section below for valid Roc.

Code

module []

# Match an empty list
expect
    match = |input|
        when input is
            [] -> EmptyList
            _ -> Other

    match([]) == EmptyList and match([A, B, C]) == Other

# Match a non-empty list
expect
    match = |input|
        when input is
            [_, ..] -> NonEmptyList
            _ -> Other

    match([A, B, C]) == NonEmptyList and match([]) == Other

# Match a list whose first element is the string "Hi"
expect
    match = |input|
        when input is
            ["Hi", ..] -> StartsWithHi
            _ -> Other

    match(["Hi", "Hello", "Yo"]) == StartsWithHi and match(["Hello", "Yo", "Hi"]) == Other

# Match a list whose last element is the number 42
expect
    match = |input|
        when input is
            [.., 42] -> EndsWith42
            _ -> Other

    match([24, 64, 42]) == EndsWith42 and match([42, 1, 5]) == Other

# Match a list that starts with a Foo tag
# followed by a Bar tag
expect
    match = |input|
        when input is
            [Foo, Bar, ..] -> StartsWithFooBar
            _ -> Other

    match([Foo, Bar, Bar]) == StartsWithFooBar and match([Bar, Bar, Foo]) == Other

# Match a list with these exact elements:
# Foo, Bar, and then (Baz "Hi")
expect
    match = |input|
        when input is
            [Foo, Bar, Baz("Hi")] -> FooBarBazStr
            _ -> Other

    match([Foo, Bar, Baz("Hi")])
    == FooBarBazStr
    and
    match([Foo, Bar])
    == Other
    and
    match([Foo, Bar, Baz("Hi"), Blah])
    == Other

# Match a list with Foo as its first element, and
# Count for its second element. Count holds a number,
# and we only match if that number is greater than 0.
expect
    match = |input|
        when input is
            [Foo, Count(num), ..] if num > 0 -> FooCountIf
            _ -> Other

    match([Foo, Count(1)])
    == FooCountIf
    and match([Foo, Count(0)])
    == Other
    and match([Baz, Count(1)])
    == Other

# Use `as` to create a variable equal to the part of the list that matches `..`
expect
    match = |input|
        when input is
            [head, .. as tail] -> HeadAndTail(head, tail)
            _ -> Other

    match([1, 2, 3])
    == HeadAndTail(1, [2, 3])
    and match([1, 2])
    == HeadAndTail(1, [2])
    and match([1])
    == HeadAndTail(1, [])
    and match([])
    == Other

Output

Run this from the directory that has PatternMatching.roc in it:

$ roc test PatternMatching.roc

0 failed and 8 passed in 88 ms.