GHC supports an extension of pattern matching called bang patterns. Bang patterns are under consideration for Haskell Prime. The Haskell prime feature description contains more discussion and examples than the material below.
Bang patterns are enabled by the flag -XBangPatterns
.
The main idea is to add a single new production to the syntax of patterns:
pat ::= !pat
Matching an expression e
against a pattern !p
is done by first
evaluating e
(to WHNF) and then matching the result against p
.
Example:
f1 !x = True
This definition makes f1
is strict in x
,
whereas without the bang it would be lazy.
Bang patterns can be nested of course:
f2 (!x, y) = [x,y]
Here, f2
is strict in x
but not in
y
.
A bang only really has an effect if it precedes a variable or wild-card pattern:
f3 !(x,y) = [x,y] f4 (x,y) = [x,y]
Here, f3
and f4
are identical; putting a bang before a pattern that
forces evaluation anyway does nothing.
Bang patterns work in case
expressions too, of course:
g5 x = let y = f x in body g6 x = case f x of { y -> body } g7 x = case f x of { !y -> body }
The functions g5
and g6
mean exactly the same thing.
But g7
evaluates (f x)
, binds y
to the
result, and then evaluates body
.
Bang patterns work in let
and where
definitions too. For example:
let ![x,y] = e in b
is a strict pattern: operationally, it evaluates e
, matches
it against the pattern [x,y]
, and then evaluates b
The "!
" should not be regarded as part of the pattern; after all,
in a function argument ![x,y]
means the
same as [x,y]
. Rather, the "!
"
is part of the syntax of let
bindings.
We add a single new production to the syntax of patterns:
pat ::= !pat
There is one problem with syntactic ambiguity. Consider:
f !x = 3
Is this a definition of the infix function "(!)
",
or of the "f
" with a bang pattern? GHC resolves this
ambiguity in favour of the latter. If you want to define
(!)
with bang-patterns enabled, you have to do so using
prefix notation:
(!) f x = 3
The semantics of Haskell pattern matching is described in Section 3.17.2 of the Haskell Report. To this description add one extra item 10, saying:
Matching
the pattern !pat
against a value v
behaves as follows:
if v
is bottom, the match diverges
otherwise, pat
is matched against
v
Similarly, in Figure 4 of Section 3.17.3, add a new case (t):
case v of { !pat -> e; _ -> e' } = v `seq` case v of { pat -> e; _ -> e' }
That leaves let expressions, whose translation is given in
Section
3.12
of the Haskell Report.
In the translation box, first apply
the following transformation: for each pattern pi
that is of
form !qi = ei
, transform it to (xi,!qi) = ((),ei)
, and and replace e0
by (xi `seq` e0)
. Then, when none of the left-hand-side patterns
have a bang at the top, apply the rules in the existing box.
The effect of the let rule is to force complete matching of the pattern
qi
before evaluation of the body is begun. The bang is
retained in the translated form in case qi
is a variable,
thus:
let !y = f x in b
The let-binding can be recursive. However, it is much more common for
the let-binding to be non-recursive, in which case the following law holds:
(let !p = rhs in body)
is equivalent to
(case rhs of !p -> body)
A pattern with a bang at the outermost level is not allowed at the top level of a module.