summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKrzysztof Gogolewski <krzysztof.gogolewski@tweag.io>2021-06-23 20:34:28 +0200
committerKrzysztof Gogolewski <krzysztof.gogolewski@tweag.io>2021-07-27 18:28:18 +0200
commit538901b3a8c44b18075fb4b1bb081227d9a85441 (patch)
tree6cdd4e4fccf41f31f6dfa301bdb83dde005fd0e1
parent773c0eaf4d7ccf1ccf99df6c3b31da48de87b746 (diff)
downloadhaskell-538901b3a8c44b18075fb4b1bb081227d9a85441.tar.gz
Improve docs of bang patterns (#19068)
-rw-r--r--docs/users_guide/exts/strict.rst105
1 files changed, 62 insertions, 43 deletions
diff --git a/docs/users_guide/exts/strict.rst b/docs/users_guide/exts/strict.rst
index a623fe7070..4e0cb61bdc 100644
--- a/docs/users_guide/exts/strict.rst
+++ b/docs/users_guide/exts/strict.rst
@@ -44,10 +44,8 @@ Bang patterns
Allow use of bang pattern syntax.
GHC supports an extension of pattern matching called *bang patterns*,
-written ``!pat``. Bang patterns are under consideration for Haskell
-Prime. The `Haskell prime feature
-description <https://gitlab.haskell.org/haskell/prime/-/wikis/BangPatterns>`__
-contains more discussion and examples than the material below.
+written ``!pat``. Bang patterns are available by default as a part
+of :extension:`GHC2021`.
The main idea is to add a single new production to the syntax of
patterns: ::
@@ -61,35 +59,72 @@ 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: ::
+bang it would be lazy.
- f2 (!x, y) = [x,y]
+Note the following points:
-Here, ``f2`` is strict in ``x`` but not in ``y``.
+- Bang patterns can be nested: ::
-Note the following points:
+ 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: ::
+- Bang patterns can be used in ``case`` expressions too: ::
+
+ g1 x = let y = f x in body
+ g2 x = case f x of { y -> body }
+ g3 x = case f x of { !y -> body }
+
+ The functions ``g1`` and ``g2`` mean exactly the same thing. But ``g3``
+ evaluates ``(f x)``, binds ``y`` to the result, and then evaluates
+ ``body``.
+
+- Bang patterns do not have any effect with constructor patterns: ::
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.
+ that forces evaluation anyway does nothing. However, see the caveat below.
+
+- 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 by looking at the surrounding
+ whitespace: ::
+
+ a ! b = ... -- infix operator
+ a !b = ... -- bang pattern
+
+ See `GHC Proposal #229 <https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0229-whitespace-bang-patterns.rst>`__
+ for the precise rules.
-- A bang pattern is allowed in a let or where clause, and makes the binding
- strict. For example: ::
+Strict bindings
+~~~~~~~~~~~~~~~
+
+The ``BangPatterns`` extension furthermore enables syntax for strict
+``let`` or ``where`` bindings with ``!pat = expr``. For example, ::
let !x = e in body
let !(p,q) = e in body
- In both cases ``e`` is evaluated before starting to evaluate ``body``.
+In both cases ``e`` is evaluated before starting to evaluate ``body``.
+
+Note the following points:
+
+- This form is not the same as a bang pattern:
+ The declarations ``f3 (x,y) = ...`` and ``f4 !(x,y) = ....``
+ are equivalent (because the constructor pattern ``(x,y)`` forces the argument),
+ but the expressions ``let (p,q) = e in body`` and ``let !(p,q) = e in body``
+ are different. The former will not evaluate ``e`` unless
+ ``p`` or ``q`` is forced in ``body``.
- However, *nested* bangs in a let/where pattern binding behave uniformly with all
- other forms of pattern matching. For example ::
+- Only a top-level bang (perhaps under parentheses) makes the binding strict; otherwise,
+ it is considered a normal bang pattern. For example, ::
- let (!x,[y]) = e in b
+ let (!x,[y]) = e in b
is equivalent to this: ::
@@ -102,35 +137,19 @@ Note the following points:
``b`` the entire pattern is matched, including forcing the evaluation of
``x``.
- See :ref:`Semantics of let bindings with bang patterns <recursive-and-polymorphic-let-bindings>` for
- the detailed semantics.
-
-- A pattern with a bang at the outermost level is not allowed at the top
- level of a module.
+- Because the ``!`` in a strict binding is not a bang pattern, it must
+ be visible without looking through pattern synonyms ::
-- Bang patterns work in ``case`` expressions too, of course: ::
+ pattern Bang x <- !x
+ f1 = let Bang x = y in ...
+ f2 = let !x = y in ... -- not equivalent to f1
- g5 x = let y = f x in body
- g6 x = case f x of { y -> body }
- g7 x = case f x of { !y -> body }
+- Strict bindings are not allowed at the top level of a module.
- The functions ``g5`` and ``g6`` mean exactly the same thing. But ``g7``
- evaluates ``(f x)``, binds ``y`` to the result, and then evaluates
- ``body``.
-
-- 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 by looking at the surrounding
- whitespace: ::
-
- a ! b = ... -- infix operator
- a !b = ... -- bang pattern
-
- See `GHC Proposal #229 <https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0229-whitespace-bang-patterns.rst>`__
- for the precise rules.
+- See :ref:`Semantics of let bindings with bang patterns <recursive-and-polymorphic-let-bindings>` for
+ the detailed semantics, and the `Haskell prime feature
+ description <https://gitlab.haskell.org/haskell/prime/-/wikis/BangPatterns>`__
+ for more discussion and examples.
.. _strict-data: