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 that 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])
    != EmptyList

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

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

# 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"])
    != StartsWithHi

# 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])
    != EndsWith42

# 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])
    != StartsWithFooBar

# 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])
    != FooBarBazStr
    and match([Foo, Bar, Baz("Hi"), Blah])
    != FooBarBazStr

# 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)])
    != FooCountIf
    and match([Baz, Count(1)])
    != FooCountIf

# 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.