diff options
author | Krzysztof Gogolewski <krzysztof.gogolewski@tweag.io> | 2021-06-23 20:34:28 +0200 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2021-07-28 13:18:31 -0400 |
commit | 2625d48efb6dc19506f1404cc5b0ec0e1b476a17 (patch) | |
tree | cded7e6a422a96d84e7f37db733cedcea588a4ef /docs/users_guide | |
parent | dabe61138a561e9a82961f81dbe276f9d909c1a7 (diff) | |
download | haskell-2625d48efb6dc19506f1404cc5b0ec0e1b476a17.tar.gz |
Improve docs of bang patterns (#19068)
Diffstat (limited to 'docs/users_guide')
-rw-r--r-- | docs/users_guide/exts/strict.rst | 105 |
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: |