Skip to content

Commit 230bfed

Browse files
Add documentation for GHC-38520 (Redundant Bang Patterns) (#528)
* Add documentation for GHC-38520 (Redundant Bang Patterns) Fixes #177 * Some slight editing --------- Co-authored-by: David Binder <[email protected]>
1 parent 975184a commit 230bfed

File tree

10 files changed

+152
-0
lines changed

10 files changed

+152
-0
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module AlreadyDeconstructed where
2+
3+
doubleIfTrue :: (Int, Bool) -> Int
4+
doubleIfTrue (x, y) | y = x * 2
5+
doubleIfTrue x = fst x
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module AlreadyDeconstructed where
2+
3+
doubleIfTrue :: (Int, Bool) -> Int
4+
doubleIfTrue (x, y) | y = x * 2
5+
doubleIfTrue !x = fst x
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
title: Already deconstructed
3+
---
4+
5+
## Warning message
6+
7+
```
8+
AlreadyDeconstructed.hs:5:15: warning: [-Wredundant-bang-patterns]
9+
Pattern match has redundant bang
10+
In an equation for ‘doubleIfTrue’: doubleIfTrue x = ...
11+
|
12+
5 | doubleIfTrue !x = fst x
13+
| ^
14+
```
15+
16+
## Explanation
17+
18+
It is possible that a previous clause already forced the evaluation of an expression.
19+
For example, `doubleIfTrue`'s first clause already deconstructs the pair tuple, so
20+
a bang pattern on the tuple as a whole has no effect in the second clause.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
title: Redundant Bang Patterns
3+
summary: Used a bang pattern that has no effect
4+
severity: warning
5+
flag: -Wredundant-bang-patterns
6+
introduced: 9.6.1
7+
---
8+
9+
The `BangPatterns` extension allows the user to mark parts of a pattern as strict by prefixing the pattern with an exclamation mark.
10+
By default, Haskell only evaluates an expression as little as it needs to determine whether the pattern matches or not.
11+
Using bang patterns causes the matched expression to always be evaluated to weak head normal
12+
form (WHNF) before the rest of the clauses, any guard patterns, or the right-hand side
13+
of the clause are executed.
14+
15+
However, there are cases where a bang pattern can be redundant.
16+
This happens either because a previous match clause already forced the evaluation, because the user is
17+
trying to match on a strict field of a data type, or because the type of the value being
18+
matched on is of an unlifted or unboxed type like `Int#` or `Array#`.
19+
20+
In all of these cases, the Bang Pattern has no added effect, so it is redundant.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module StrictField where
2+
3+
data Foo = MkFoo !Int Int
4+
5+
foo :: Foo -> Foo -> ()
6+
foo !a (MkFoo b !c) = ()
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module StrictField where
2+
3+
data Foo = MkFoo !Int Int
4+
5+
foo :: Foo -> Foo -> ()
6+
foo !a (MkFoo !b !c) = ()
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
title: Strict fields
3+
---
4+
5+
## Warning message
6+
7+
```
8+
UnliftedTypes.hs:17:6: warning: [-Wredundant-bang-patterns]
9+
Pattern match has redundant bang
10+
In an equation for ‘foo’: foo a = ...
11+
|
12+
17 | foo !a !b !c = ()
13+
| ^
14+
```
15+
16+
## Explanation
17+
18+
Haskell allows a user to annotate fields of a datatype as strict, by prepending
19+
their type with an exclamation mark.
20+
Pattern matching on such a constructor forces it to WHNF, but this also automatically
21+
forces any strict fields to evaluate to WHNF as well.
22+
Thus, a Bang Pattern has no effect on a strict field.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{-# LANGUAGE BangPatterns #-}
2+
{-# LANGUAGE DataKinds #-}
3+
{-# LANGUAGE MagicHash #-}
4+
{-# LANGUAGE GADTs #-}
5+
{-# LANGUAGE KindSignatures #-}
6+
{-# LANGUAGE UnboxedTuples #-}
7+
{-# LANGUAGE UnliftedNewtypes #-}
8+
9+
module UnliftedTypes where
10+
11+
import GHC.Exts
12+
13+
newtype MyInt :: TYPE 'IntRep where
14+
MkMyInt :: Int# -> MyInt
15+
16+
foo :: Int# -> MyInt -> (# Int, Int #) -> ()
17+
foo a b c = ()
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{-# LANGUAGE BangPatterns #-}
2+
{-# LANGUAGE DataKinds #-}
3+
{-# LANGUAGE MagicHash #-}
4+
{-# LANGUAGE GADTs #-}
5+
{-# LANGUAGE KindSignatures #-}
6+
{-# LANGUAGE UnboxedTuples #-}
7+
{-# LANGUAGE UnliftedNewtypes #-}
8+
9+
module UnliftedTypes where
10+
11+
import GHC.Exts
12+
13+
newtype MyInt :: TYPE 'IntRep where
14+
MkMyInt :: Int# -> MyInt
15+
16+
foo :: Int# -> MyInt -> (# Int, Int #) -> ()
17+
foo !a !b !c = ()
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
title: Unlifted and unboxed types
3+
---
4+
5+
## Warning messages
6+
7+
```
8+
UnliftedTypes.hs:17:6: warning: [-Wredundant-bang-patterns]
9+
Pattern match has redundant bang
10+
In an equation for ‘foo’: foo a = ...
11+
|
12+
17 | foo !a !b !c = ()
13+
| ^
14+
15+
UnliftedTypes.hs:17:9: warning: [-Wredundant-bang-patterns]
16+
Pattern match has redundant bang
17+
In an equation for ‘foo’: foo b = ...
18+
|
19+
17 | foo !a !b !c = ()
20+
| ^
21+
22+
UnliftedTypes.hs:17:12: warning: [-Wredundant-bang-patterns]
23+
Pattern match has redundant bang
24+
In an equation for ‘foo’: foo c = ...
25+
|
26+
17 | foo !a !b !c = ()
27+
| ^
28+
```
29+
30+
## Explanation
31+
32+
Forcing the evaluation of a value up to WHNF does not make sense for unlifted and
33+
unboxed types, because these types can never be represented by an unevaluated expression at runtime.
34+
Thus, trying to enforce strictness via a bang pattern has no effect.

0 commit comments

Comments
 (0)