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
| Form | Written | Matches |
|---|---|---|
| wildcard | _ | any value, binding nothing |
| variable | count | any value, binding it under that name |
| literal | 0, 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 |
| constructor | Dot, Circle n, S.Dot | a value built by that constructor, each argument against its own pattern |
| as-pattern | Circle n as whole | whatever its left side matches, also binding the whole value |
| list | [], [a, b] | a list of exactly that length |
| cons | first :: rest | a 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 |
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 ->
nWhere 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.
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 ->
OnNot 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:
module Example exposing (Flag, invert)
type Flag
= On
| Off
invert : Flag -> Flag
invert On = Off
invert Off = OnNot 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:
module Example exposing (Flag, ignore)
type Flag
= On
| Off
ignore : Flag -> Flag
ignore flag =
case flag of
On ->
OffKnown 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.
module Example exposing (Flag, Triple, middle)
type Flag
= On
| Off
type Triple
= Triple Flag Flag Flag
middle : Triple -> Flag
middle (Triple _ b _) =
bAn 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:
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
innerA pattern variable shadows anything of the same name from an enclosing scope, including a top-level declaration in the same module:
module Example exposing (Flag, count, f)
type Flag
= On
| Off
count : Flag
count =
On
f : Flag -> Flag
f count =
countA 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.
module Example exposing (Flag, Pair, same)
type Flag
= On
| Off
type Pair
= Pair Flag Flag
same : Pair -> Flag
same (Pair a a) =
aKnown 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:
module Example exposing (Flag, pick)
type Flag
= On
| Off
pick : Flag -> Flag -> Flag
pick a a =
apick 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.
module Example exposing (Flag)
type Flag
= On
| Off
isVowel c =
case c of
'a' ->
On
'e' ->
On
_ ->
OffA 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.
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
_ ->
OffA case whose pattern has a different type from the value it matches is a type error:
module Example exposing (answer)
answer : Int
answer =
case 1 of
"a" ->
1
_ ->
0module Example exposing (answer)
answer : Int
answer =
case 1 of
0.5 ->
1
_ ->
0A 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.
module Example exposing (Flag)
type Flag
= On
| Off
sign n =
case n of
-1 ->
On
_ ->
OffNot 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.
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:
module Example exposing (Flag)
type Flag
= On
| Off
first (a, b, c, d) =
aParentheses 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:
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 ->
OneIn a function declaration's head, juxtaposition already separates one parameter from the next, so an applied constructor must be parenthesised:
module Example exposing (Count, Boxed, unbox)
type Count
= One
| Many
type Boxed
= Boxed Count
unbox : Boxed -> Count
unbox (Boxed n) =
nA constructor with no arguments needs no parentheses there, because there is nothing for juxtaposition to be ambiguous about:
module Example exposing (Unit, identity)
type Unit
= Unit
identity : Unit -> Unit
identity Unit =
UnitDropping 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:
module Example exposing (Count, Shape, width)
type Count
= One
| Many
type Shape
= Dot
| Rect Count Count
width : Shape -> Count
width Dot n =
OneTypes 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.
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 ->
OneKnown 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.
module Shape exposing (Count(..), Shape(..))
type Count
= One
| Many
type Shape
= Dot
| Circle Countmodule Main exposing (describe)
import Shape as S
describe : S.Shape -> S.Count
describe shape =
case shape of
S.Circle n ->
n
S.Dot ->
S.OneA constructor that is not in scope is reported as such, with the caret under the name:
module Example exposing (Flag, f)
type Flag
= On
| Off
f : Flag -> Flag
f flag =
case flag of
Onn ->
Off
_ ->
OnPatterns 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:
| Written | Read as |
|---|---|
Circle n :: rest | (Circle n) :: rest |
a :: b :: rest | a :: (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:
| Position | Ended by | Example |
|---|---|---|
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:
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
_ ->
OneNot 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:
module Example exposing (Flag, both)
type Flag
= On
| Off
both : (Flag, Flag) -> Flag
both pair =
case pair of
(On, On) ->
On
_ ->
OffAn applied constructor as a constructor's argument:
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
_ ->
OneA parenthesised constructor pattern at the head of a case branch:
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 ->
OneAs-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.
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 ->
DotNot 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:
module Example exposing (dropFirst)
dropFirst xs =
case xs of
[] ->
xs
_ :: rest ->
restA 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:
module Example exposing (Flag)
type Flag
= On
| Off
firstOf xs =
case xs of
[] ->
Off
[only] ->
only
_ ->
OnNot 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.
module Example exposing (Flag, always)
type Flag
= On
| Off
always : () -> Flag
always () =
OnRecord 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.
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 } ->
expectedA 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.