Patterns

A pattern is a shape written where a value will arrive. Matching a value against a pattern asks whether the value has that shape and, if it does, what the names for its parts are. Circle n matches a value built by Circle and binds n to what it was built from; _ matches anything and binds nothing.

Pattern syntax is closed: the forms below are all of them, and no declaration adds another. That is the difference between a pattern and an expression: an expression is made of names, and an operator in one is a name someone bound with an infix declaration, so what a + b means depends on what is in scope. A pattern looks up exactly one kind of name — a type constructor — and everything else about it is fixed by the grammar. A reader can therefore tell what a pattern matches by looking at it, without knowing which module it is in.

The forms

FormWrittenMatches
wildcard_any value, binding nothing
variablecountany value, binding it under that name
literal0, 1.5, 'x', "ok"a value equal to that literal
tuple(a, b), (a, b, c)a tuple of that arity, each element against its own pattern
constructorDot, Circle n, S.Dota value built by that constructor, each argument against its own pattern
as-patternCircle n as wholewhatever its left side matches, also binding the whole value
list[], [a, b]a list of exactly that length
consfirst :: resta non-empty list, split into its first element and the rest
unit()the one value of the unit type
record{ x = p }, { x }a record, each named field against its own pattern
expect=ok
module Example exposing (Count, Shape, describe)

type Count
  = One
  | Many

type Shape
  = Dot
  | Circle Count

describe : Shape -> Count
describe shape =
  case shape of
    Dot ->
      One

    Circle n ->
      n

Where a pattern may appear

A pattern appears in two places: as a parameter in a function declaration's head, and as the left-hand side of a case branch.

expect=ok
module Example exposing (Flag, Pair, first, invert)

type Flag
  = On
  | Off

type Pair
  = Pair Flag Flag

first : Pair -> Flag
first (Pair a b) =
  a

invert : Flag -> Flag
invert flag =
  case flag of
    On ->
      Off

    Off ->
      On

Not implemented: a pattern will also stand on the left of a let binding and as a lambda's parameter. Neither construct exists yet; see Layout.

A pattern that can fail, and one that cannot

A pattern is irrefutable when every value of the type it is written against matches it, and refutable otherwise. The wildcard and a variable are always irrefutable. A tuple pattern is irrefutable exactly when all of its elements are. A literal pattern is always refutable, and so is every list pattern, the cons form included. A constructor pattern is irrefutable only when its type has that one constructor and its arguments are themselves irrefutable.

Both positions accept both kinds. The language requires the patterns in a position to cover the type between them — a case with its branches, a function declaration with its clauses. Both are tried in the order written, so an earlier branch or clause wins over a later one that would also have matched:

expect=canonical-error:MultipleBindingsUnsupported
module Example exposing (Flag, invert)

type Flag
  = On
  | Off

invert : Flag -> Flag
invert On = Off
invert Off = On

Not implemented: a declaration may be written as several clauses, one per line, each with its own patterns and its own body. Every clause names the same number of parameters. The compiler parses them and then reports that a name declared over more than one binding is not supported, so today a declaration has exactly one clause and any pattern that can fail has to go in a case. docs/tickets/lang-20.md is the ticket.

Coverage is checked rather than assumed:

expect=ok
module Example exposing (Flag, ignore)

type Flag
  = On
  | Off

ignore : Flag -> Flag
ignore flag =
  case flag of
    On ->
      Off

Known gap: that block should be rejected — the case has no branch for Off, so ignore Off has no value to produce. Nothing checks coverage today: the exhaustiveness phase inspects nothing and accepts every module. docs/tickets/lang-19.md is the ticket.

The wildcard

_ matches any value and binds nothing. It is the way to say that a position is deliberately ignored, and it may be written as many times in one pattern as there are positions to ignore — it introduces no name, so two of them cannot collide.

expect=ok
module Example exposing (Flag, Triple, middle)

type Flag
  = On
  | Off

type Triple
  = Triple Flag Flag Flag

middle : Triple -> Flag
middle (Triple _ b _) =
  b

An ignored position has to use the wildcard and cannot use a variable name preceded by an underscore: _count is not a legal pattern. See Lexical structure.

Variable patterns

A lowercase-initial identifier matches any value and binds it under that name, for the body it belongs to and no further. A case branch's bindings are visible in that branch's expression alone:

expect=canonical-error:VariableNotFound
module Example exposing (Flag, f, g)

type Flag
  = On
  | Off

f : Flag -> Flag
f flag =
  case flag of
    inner ->
      -- legal: `inner` is the branch that bound it
      inner

g : Flag
g =
  -- rejected: the branch above ended, and its bindings ended with it
  inner

A pattern variable shadows anything of the same name from an enclosing scope, including a top-level declaration in the same module:

expect=ok
module Example exposing (Flag, count, f)

type Flag
  = On
  | Off

count : Flag
count =
  On

f : Flag -> Flag
f count =
  count

A pattern binds each name once

Every variable in one pattern position is distinct. Repeating a name is an error rather than a demand that the two values be equal — a pattern describes a shape, and equality is a question about values that a body asks with an operator.

expect=ok
module Example exposing (Flag, Pair, same)

type Flag
  = On
  | Off

type Pair
  = Pair Flag Flag

same : Pair -> Flag
same (Pair a a) =
  a

Known gap: that block should be rejected. Canonicalization inserts each of a pattern's variables into the branch's scope in turn, so the second a silently replaces the first and the body sees the second field. docs/tickets/lang-18.md is the ticket.

The rule spans a whole clause, not one pattern. A declaration's parameters are separate patterns but one binding position between them, so repeating a name across two parameters is the same error:

expect=ok
module Example exposing (Flag, pick)

type Flag
  = On
  | Off

pick : Flag -> Flag -> Flag
pick a a =
  a

pick takes two arguments and its body names a, which could mean either of them — there is no rule that picks one, so the declaration is rejected.

Known gap: that block should be rejected too, and for the same reason as the one above: the two parameter patterns are exposed into the scope one after another, so the second a replaces the first and the body sees the second argument. docs/tickets/lang-18.md covers both.

Literal patterns

Any literal (integer, float, character or string) matches a value equal to it. The literal is written exactly as it is in an expression; see Lexical structure for what each may contain.

expect=ok
module Example exposing (Flag)

type Flag
  = On
  | Off

isVowel c =
  case c of
    'a' ->
      On

    'e' ->
      On

    _ ->
      Off

A literal pattern has the type of the literal it spells, so the value it is matched against has that type: a Float pattern matches a Float and a String pattern a String.

expect=ok
module Example exposing (Flag, isHalf)

type Flag
  = On
  | Off

greeting s =
  case s of
    "hello" ->
      On

    _ ->
      Off

isHalf : Float -> Flag
isHalf x =
  case x of
    0.5 ->
      On

    _ ->
      Off

A case whose pattern has a different type from the value it matches is a type error:

expect=type-error
module Example exposing (answer)

answer : Int
answer =
  case 1 of
    "a" ->
      1

    _ ->
      0
expect=type-error
module Example exposing (answer)

answer : Int
answer =
  case 1 of
    0.5 ->
      1

    _ ->
      0

A Float pattern matches a value equal to it as structural equality compares two Floats, which is IEEE 754's comparison: the pattern 0.0 matches -0.0 as well as 0.0, and no float literal matches nan, so a nan is matched only by a variable or a wildcard pattern.

A literal pattern is refutable, so it needs a branch after it that covers the rest of the type — which for a literal type means a wildcard or a variable, since no finite list of literals covers one.

A pattern may hold a negative number. The pattern grammar carries the sign, not the token underneath it: pattern syntax is closed, and - in an expression is a name bound by an infix declaration, which a pattern never looks up, so there is nothing available to apply it to. A leading - immediately before a literal pattern is consumed by the pattern production itself, not by the tokenizer — Lexical structure is where the integer token is specified, and that token never carries a sign, in a pattern or anywhere else.

expect=unimplemented
module Example exposing (Flag)

type Flag
  = On
  | Off

sign n =
  case n of
    -1 ->
      On

    _ ->
      Off

Not implemented: the grammar reaches for a pattern after the branch's opening and finds the -, so a signed literal is a syntax error.

There is no boolean literal: True and False are ordinary constructors of an ordinary union type, so a boolean pattern is a constructor pattern like any other. See Lexical structure.

Tuple patterns

A tuple pattern has two or three elements, matching the tuple types the language has and no others. Each element is a pattern of its own.

expect=ok
module Example exposing (Flag, swap)

type Flag
  = On
  | Off

swap : (Flag, Flag) -> (Flag, Flag)
swap (a, b) =
  (b, a)

The two-or-three limit and the reasoning behind it are in Types; it holds in pattern position exactly as it does in type position, so a four-element tuple pattern is a syntax error rather than a type error:

expect=parse-error:UnexpectedToken
module Example exposing (Flag)

type Flag
  = On
  | Off

first (a, b, c, d) =
  a

Parentheses with one pattern inside are grouping and not a tuple of one — (p) is p.

Constructor patterns

A constructor pattern names a type constructor and gives one pattern per argument it was declared with. It matches a value built by that constructor, and matches each argument against the pattern in that position.

Whether the constructor's arguments may be written without parentheses depends on the position, and the rule for every position is below. In a case branch the whole left-hand side is one pattern, so a constructor and its arguments read as one thing:

expect=ok
module Example exposing (Count, Shape, width)

type Count
  = One
  | Many

type Shape
  = Dot
  | Rect Count Count

width : Shape -> Count
width shape =
  case shape of
    Rect w h ->
      w

    Dot ->
      One

In a function declaration's head, juxtaposition already separates one parameter from the next, so an applied constructor must be parenthesised:

expect=ok
module Example exposing (Count, Boxed, unbox)

type Count
  = One
  | Many

type Boxed
  = Boxed Count

unbox : Boxed -> Count
unbox (Boxed n) =
  n

A constructor with no arguments needs no parentheses there, because there is nothing for juxtaposition to be ambiguous about:

expect=ok
module Example exposing (Unit, identity)

type Unit
  = Unit

identity : Unit -> Unit
identity Unit =
  Unit

Dropping the parentheses means width Dot n below is a well-formed head of two parameters: a nullary constructor pattern and a variable. Nothing about the patterns is wrong; what rejects it is the annotation, which promises one parameter:

expect=canonical-error:BindingPatternsInvalidLen
module Example exposing (Count, Shape, width)

type Count
  = One
  | Many

type Shape
  = Dot
  | Rect Count Count

width : Shape -> Count
width Dot n =
  One

Types is where that check is specified. A declaration with no annotation has nothing to disagree with, so it takes however many parameters its head names — and dropping the parentheses there changes its arity.

The arguments must be the ones it was declared with

A constructor pattern must supply exactly as many argument patterns as the type declaration gave that constructor.

expect=ok
module Example exposing (Count, Shape, width)

type Count
  = One
  | Many

type Shape
  = Dot
  | Rect Count Count

width : Shape -> Count
width shape =
  case shape of
    Rect w ->
      w

    Dot ->
      One

Known gap: that block should be rejected — Rect has two arguments and the pattern gives one. No phase checks: canonicalization resolves the constructor without counting, and the type checker pairs argument patterns with declared parameter types by zipping the two lists, which stops at the shorter. A pattern with too many arguments is accepted the same way, and the extra ones bind nothing. docs/tickets/lang-17.md is the ticket.

Qualified constructors

A constructor pattern may name its constructor qualified, under the module's name or under the alias the import gave it. The rule is the one every name follows; see Modules.

expect=okpackage=qualified
module Shape exposing (Count(..), Shape(..))

type Count
  = One
  | Many

type Shape
  = Dot
  | Circle Count
expect=okpackage=qualified
module Main exposing (describe)

import Shape as S

describe : S.Shape -> S.Count
describe shape =
  case shape of
    S.Circle n ->
      n

    S.Dot ->
      S.One

A constructor that is not in scope is reported as such, with the caret under the name:

expect=canonical-error:VariantNotFound
module Example exposing (Flag, f)

type Flag
  = On
  | Off

f : Flag -> Flag
f flag =
  case flag of
    Onn ->
      Off

    _ ->
      On

Patterns nest

Every pattern position takes a pattern, so patterns nest to any depth: a constructor argument may be a tuple or another constructor pattern, and a tuple element may be a constructor pattern.

Where a pattern is parenthesised

Three forms have nothing in their own spelling that ends them: a constructor applied to arguments, a cons pattern and an as-pattern. They group the way their counterparts in an expression do. A constructor's arguments bind tightest, then ::, which groups rightward, then as:

WrittenRead as
Circle n :: rest(Circle n) :: rest
a :: b :: resta :: (b :: rest)
first :: rest as whole(first :: rest) as whole

An argument position is a constructor's argument or a parameter. Juxtaposition alone separates one argument from the next, so any of the three forms written there must be parenthesised: Wrapper (Circle n), Wrapper (shape as whole), and total (first :: rest) in a declaration's head. Parentheses are also how a looser form becomes the operand of a tighter one, as in (first as whole) :: rest.

Every other position is ended by a token, and takes any pattern without parentheses:

PositionEnded byExample
the left-hand side of a case branch->Circle n ->
a tuple pattern's element, or )(Circle n, Dot)
a record pattern's entry, or }{ taken = Celsius t }
a bracketed list pattern's element, or ][Circle n, _]

Parentheses around one pattern are grouping wherever they are written, so a pattern that needs none may still carry them.

An applied constructor as a tuple element:

expect=unimplemented
module Example exposing (Count, Shape, first)

type Count
  = One
  | Many

type Shape
  = Dot
  | Circle Count

first : (Shape, Shape) -> Count
first pair =
  case pair of
    (Circle n, _) ->
      n

    _ ->
      One

Not implemented: a tuple pattern's element and a record pattern's entry are read as an argument position is, so an applied constructor there is a syntax error and ((Circle n), _) is the spelling that parses. docs/tickets/lang-89.md is the ticket.

A nullary constructor as a tuple element:

expect=ok
module Example exposing (Flag, both)

type Flag
  = On
  | Off

both : (Flag, Flag) -> Flag
both pair =
  case pair of
    (On, On) ->
      On

    _ ->
      Off

An applied constructor as a constructor's argument:

expect=ok
module Example exposing (Count, Shape, Wrapper, inner)

type Count
  = One
  | Many

type Shape
  = Dot
  | Circle Count

type Wrapper
  = Wrapper Shape

inner : Wrapper -> Count
inner w =
  case w of
    Wrapper (Circle n) ->
      n

    _ ->
      One

A parenthesised constructor pattern at the head of a case branch:

expect=ok
module Example exposing (Count, Shape, describe)

type Count
  = One
  | Many

type Shape
  = Dot
  | Circle Count

describe : Shape -> Count
describe shape =
  case shape of
    (Circle n) ->
      n

    Dot ->
      One

As-patterns

A pattern may be given a name for the whole value it matched, written pattern as name. The sub-patterns bind their parts as usual and the name binds what they were taken from, so a branch can inspect a value and pass it on without rebuilding it.

as binds more loosely than everything else in a pattern: in Rect w h as whole, whole names the entire Rect, not h. It is parenthesised in an argument position and as an operand of ::, and nowhere else.

expect=unimplemented
module Example exposing (Count, Shape, widen)

type Count
  = One
  | Many

type Shape
  = Dot
  | Rect Count Count

widen : Shape -> Shape
widen shape =
  case shape of
    Rect w h as whole ->
      whole

    Dot ->
      Dot

Not implemented: as is a reserved word but the grammar accepts it only in an import, so a pattern using it is a syntax error.

List patterns

A list pattern is a bracketed sequence of patterns and matches a list of exactly that length, element by element. [] matches the empty list, [a] a list of one, [a, b] a list of two.

A cons pattern, first :: rest, matches a list of one element or more: it binds the first element to the pattern on the left and the rest of the list — possibly empty — to the pattern on the right. :: groups rightward, so a :: b :: rest matches a list of two or more, and a constructor's arguments bind tighter than ::, so Circle n :: rest matches on the first element's shape. Where a pattern is parenthesised has the rule for both forms as sub-patterns: a bracket pattern is delimited and never needs parentheses, and a cons pattern needs them in an argument position.

:: here is a form of the grammar and not a name — in an expression it is an ordinary operator, and Lists is where the two halves are set beside each other. Pattern syntax is closed, so a pattern never looks up an operator: :: separates a head from a tail the way , separates tuple elements, and it means that regardless of what is in scope.

Both forms are the constructor patterns of the two-variant type Lists declares — [] is the empty one, first :: rest the other — which is where their coverage below comes from.

[] and a cons pattern cover the list type between them, because every list is either empty or has a first element. A case written out of the two is complete and needs no wildcard:

expect=unimplemented
module Example exposing (dropFirst)

dropFirst xs =
  case xs of
    [] ->
      xs

    _ :: rest ->
      rest

A bracketed list pattern fixes a length. No finite set of lengths covers a list, so a case built only out of those needs a variable or a wildcard branch to be complete:

expect=unimplemented
module Example exposing (Flag)

type Flag
  = On
  | Off

firstOf xs =
  case xs of
    [] ->
      Off

    [only] ->
      only

    _ ->
      On

Not implemented: lists are not implemented in any position. Brackets are tokenized and :: tokenizes as an ordinary operator, but no pattern production consumes either (LANG-45); see Lexical structure.

The unit pattern

() matches the one value of the unit type, and binds nothing. It differs from _ in the same position by saying which type is being ignored.

expect=ok
module Example exposing (Flag, always)

type Flag
  = On
  | Off

always : () -> Flag
always () =
  On

Record patterns

A record pattern names fields rather than positions. Each entry is label = pattern and the field's value is matched against that pattern; { x } is shorthand for { x = x }, the field matched against a variable pattern of its own label.

expect=ok
module Example exposing (Celsius, describe)

type Celsius
  = Celsius

describe : { taken : Celsius, expected : Celsius } -> Celsius
describe reading =
  case reading of
    { taken = Celsius, expected = e } ->
      e

    { expected } ->
      expected

A record pattern names a subset of the record's fields, so it is refutable exactly when one of its sub-patterns is and a pattern of shorthand entries alone can never fail. An entry takes any pattern, so record patterns nest in both directions like every other form. Records is where the rest of the construct is specified.