-
Notifications
You must be signed in to change notification settings - Fork 72
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
47cfa37
commit 4e088ae
Showing
12 changed files
with
478 additions
and
2 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
messages/GHC-38520/alreadyDeconstructed/after/AlreadyDeconstructed.hs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module AlreadyDeconstructed where | ||
|
||
doubleIfTrue :: (Int, Bool) -> Int | ||
doubleIfTrue (x, y) | y = x * 2 | ||
doubleIfTrue x = fst x |
5 changes: 5 additions & 0 deletions
5
messages/GHC-38520/alreadyDeconstructed/before/AlreadyDeconstructed.hs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module AlreadyDeconstructed where | ||
|
||
doubleIfTrue :: (Int, Bool) -> Int | ||
doubleIfTrue (x, y) | y = x * 2 | ||
doubleIfTrue !x = fst x |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<h2 id="warning-message">Warning message</h2> | ||
<pre><code>AlreadyDeconstructed.hs:5:15: warning: [-Wredundant-bang-patterns] | ||
Pattern match has redundant bang | ||
In an equation for ‘doubleIfTrue’: doubleIfTrue x = ... | ||
| | ||
5 | doubleIfTrue !x = fst x | ||
| ^</code></pre> | ||
<h2 id="explanation">Explanation</h2> | ||
<p>It is possible that a previous clause already forced the evaluation of an expression. | ||
For example, <code>doubleIfTrue</code>’s first clause already deconstructs the pair tuple, so | ||
a bang pattern on the tuple as a whole has no effect in the second clause.</p> | ||
|
||
<pre class="filename">AlreadyDeconstructed.hs</pre> | ||
<div class="example-container"> | ||
<div class="example"> | ||
<div class="example-inner"> | ||
<div class="example-title">Before</div> | ||
<!-- keep next line as is, i.e., on one line, or the code will not format properly --> | ||
<pre class="example-pre"><code class="language-haskell">module AlreadyDeconstructed where | ||
|
||
doubleIfTrue :: (Int, Bool) -> Int | ||
doubleIfTrue (x, y) | y = x * 2 | ||
doubleIfTrue !x = fst x | ||
</code></pre> | ||
</div> | ||
</div> | ||
<div class="example"> | ||
<div class="example-inner"> | ||
<div class="example-title">After</div> | ||
<!-- keep next line as is, i.e., on one line, or the code will not format propertly --> | ||
<pre class="example-pre"><code class="language-haskell">module AlreadyDeconstructed where | ||
|
||
doubleIfTrue :: (Int, Bool) -> Int | ||
doubleIfTrue (x, y) | y = x * 2 | ||
doubleIfTrue x = fst x | ||
</code></pre> | ||
</div> | ||
</div> | ||
</div> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,251 @@ | ||
<!doctype html> | ||
<html lang="en"> | ||
|
||
<head> | ||
<meta charset="utf-8"> | ||
<meta http-equiv="x-ua-compatible" content="ie=edge"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<title>Redundant Bang Patterns [GHC-38520] — Haskell Error Index</title> | ||
<link rel="stylesheet" href="../../css/highlight.css"> | ||
<script src="../../js/highlight.min.js"></script> | ||
<link rel="stylesheet" href="../../css/default.css" /> | ||
<link rel="stylesheet" href="../../css/theme.css" /> | ||
</head> | ||
|
||
<body> | ||
<main role="main"> | ||
<nav class="breadcrumb"> | ||
|
||
<a href="../../">The Haskell Error Index</a> » | ||
|
||
Redundant Bang Patterns [GHC-38520] | ||
</nav> | ||
<h1>Redundant Bang Patterns [GHC-38520]</h1> | ||
|
||
<p> | ||
<i>Flag: <code>-Wredundant-bang-patterns</code></i><br /> | ||
|
||
|
||
|
||
</p> | ||
|
||
|
||
<p>The <code>BangPatterns</code> extension allows the user to mark parts of a pattern as strict by prefixing the pattern with an exclamation mark. | ||
By default, Haskell only evaluates an expression as little as it needs to determine whether the pattern matches or not. | ||
Using bang patterns causes the matched expression to always be evaluated to weak head normal | ||
form (WHNF) before the rest of the clauses, any guard patterns, or the right-hand side | ||
of the clause are executed.</p> | ||
<p>However, there are cases where a bang pattern can be redundant. | ||
This happens either because a previous match clause already forced the evaluation, because the user is | ||
trying to match on a strict field of a data type, or because the type of the value being | ||
matched on is of an unlifted or unboxed type like <code>Int#</code> or <code>Array#</code>.</p> | ||
<p>In all of these cases, the Bang Pattern has no added effect, so it is redundant.</p> | ||
|
||
|
||
|
||
<h2>Examples</h2> | ||
|
||
<details open="open"> | ||
<summary>Already deconstructed</summary> | ||
<div class="details-inner"> | ||
<h2 id="warning-message">Warning message</h2> | ||
<pre><code>AlreadyDeconstructed.hs:5:15: warning: [-Wredundant-bang-patterns] | ||
Pattern match has redundant bang | ||
In an equation for ‘doubleIfTrue’: doubleIfTrue x = ... | ||
| | ||
5 | doubleIfTrue !x = fst x | ||
| ^</code></pre> | ||
<h2 id="explanation">Explanation</h2> | ||
<p>It is possible that a previous clause already forced the evaluation of an expression. | ||
For example, <code>doubleIfTrue</code>’s first clause already deconstructs the pair tuple, so | ||
a bang pattern on the tuple as a whole has no effect in the second clause.</p> | ||
|
||
<pre class="filename">AlreadyDeconstructed.hs</pre> | ||
<div class="example-container"> | ||
<div class="example"> | ||
<div class="example-inner"> | ||
<div class="example-title">Before</div> | ||
<!-- keep next line as is, i.e., on one line, or the code will not format properly --> | ||
<pre class="example-pre"><code class="language-haskell">module AlreadyDeconstructed where | ||
|
||
doubleIfTrue :: (Int, Bool) -> Int | ||
doubleIfTrue (x, y) | y = x * 2 | ||
doubleIfTrue !x = fst x | ||
</code></pre> | ||
</div> | ||
</div> | ||
<div class="example"> | ||
<div class="example-inner"> | ||
<div class="example-title">After</div> | ||
<!-- keep next line as is, i.e., on one line, or the code will not format propertly --> | ||
<pre class="example-pre"><code class="language-haskell">module AlreadyDeconstructed where | ||
|
||
doubleIfTrue :: (Int, Bool) -> Int | ||
doubleIfTrue (x, y) | y = x * 2 | ||
doubleIfTrue x = fst x | ||
</code></pre> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
|
||
</div> | ||
</details> | ||
|
||
<details open="open"> | ||
<summary>Strict fields</summary> | ||
<div class="details-inner"> | ||
<h2 id="warning-message">Warning message</h2> | ||
<pre><code>UnliftedTypes.hs:17:6: warning: [-Wredundant-bang-patterns] | ||
Pattern match has redundant bang | ||
In an equation for ‘foo’: foo a = ... | ||
| | ||
17 | foo !a !b !c = () | ||
| ^ </code></pre> | ||
<h2 id="explanation">Explanation</h2> | ||
<p>Haskell allows a user to annotate fields of a datatype as strict, by prepending | ||
their type with an exclamation mark. | ||
Pattern matching on such a constructor forces it to WHNF, but this also automatically | ||
forces any strict fields to evaluate to WHNF as well. | ||
Thus, a Bang Pattern has no effect on a strict field.</p> | ||
|
||
<pre class="filename">StrictField.hs</pre> | ||
<div class="example-container"> | ||
<div class="example"> | ||
<div class="example-inner"> | ||
<div class="example-title">Before</div> | ||
<!-- keep next line as is, i.e., on one line, or the code will not format properly --> | ||
<pre class="example-pre"><code class="language-haskell">module StrictField where | ||
|
||
data Foo = MkFoo !Int Int | ||
|
||
foo :: Foo -> Foo -> () | ||
foo !a (MkFoo !b !c) = () | ||
</code></pre> | ||
</div> | ||
</div> | ||
<div class="example"> | ||
<div class="example-inner"> | ||
<div class="example-title">After</div> | ||
<!-- keep next line as is, i.e., on one line, or the code will not format propertly --> | ||
<pre class="example-pre"><code class="language-haskell">module StrictField where | ||
|
||
data Foo = MkFoo !Int Int | ||
|
||
foo :: Foo -> Foo -> () | ||
foo !a (MkFoo b !c) = () | ||
</code></pre> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
|
||
</div> | ||
</details> | ||
|
||
<details open="open"> | ||
<summary>Unlifted and unboxed types</summary> | ||
<div class="details-inner"> | ||
<h2 id="warning-messages">Warning messages</h2> | ||
<pre><code>UnliftedTypes.hs:17:6: warning: [-Wredundant-bang-patterns] | ||
Pattern match has redundant bang | ||
In an equation for ‘foo’: foo a = ... | ||
| | ||
17 | foo !a !b !c = () | ||
| ^ | ||
|
||
UnliftedTypes.hs:17:9: warning: [-Wredundant-bang-patterns] | ||
Pattern match has redundant bang | ||
In an equation for ‘foo’: foo b = ... | ||
| | ||
17 | foo !a !b !c = () | ||
| ^ | ||
|
||
UnliftedTypes.hs:17:12: warning: [-Wredundant-bang-patterns] | ||
Pattern match has redundant bang | ||
In an equation for ‘foo’: foo c = ... | ||
| | ||
17 | foo !a !b !c = () | ||
| ^</code></pre> | ||
<h2 id="explanation">Explanation</h2> | ||
<p>Forcing the evaluation of a value up to WHNF does not make sense for unlifted and | ||
unboxed types, because these types can never be represented by an unevaluated expression at runtime. | ||
Thus, trying to enforce strictness via a bang pattern has no effect.</p> | ||
|
||
<pre class="filename">UnliftedTypes.hs</pre> | ||
<div class="example-container"> | ||
<div class="example"> | ||
<div class="example-inner"> | ||
<div class="example-title">Before</div> | ||
<!-- keep next line as is, i.e., on one line, or the code will not format properly --> | ||
<pre class="example-pre"><code class="language-haskell">{-# LANGUAGE BangPatterns #-} | ||
{-# LANGUAGE DataKinds #-} | ||
{-# LANGUAGE MagicHash #-} | ||
{-# LANGUAGE GADTs #-} | ||
{-# LANGUAGE KindSignatures #-} | ||
{-# LANGUAGE UnboxedTuples #-} | ||
{-# LANGUAGE UnliftedNewtypes #-} | ||
|
||
module UnliftedTypes where | ||
|
||
import GHC.Exts | ||
|
||
newtype MyInt :: TYPE 'IntRep where | ||
MkMyInt :: Int# -> MyInt | ||
|
||
foo :: Int# -> MyInt -> (# Int, Int #) -> () | ||
foo !a !b !c = () | ||
</code></pre> | ||
</div> | ||
</div> | ||
<div class="example"> | ||
<div class="example-inner"> | ||
<div class="example-title">After</div> | ||
<!-- keep next line as is, i.e., on one line, or the code will not format propertly --> | ||
<pre class="example-pre"><code class="language-haskell">{-# LANGUAGE BangPatterns #-} | ||
{-# LANGUAGE DataKinds #-} | ||
{-# LANGUAGE MagicHash #-} | ||
{-# LANGUAGE GADTs #-} | ||
{-# LANGUAGE KindSignatures #-} | ||
{-# LANGUAGE UnboxedTuples #-} | ||
{-# LANGUAGE UnliftedNewtypes #-} | ||
|
||
module UnliftedTypes where | ||
|
||
import GHC.Exts | ||
|
||
newtype MyInt :: TYPE 'IntRep where | ||
MkMyInt :: Int# -> MyInt | ||
|
||
foo :: Int# -> MyInt -> (# Int, Int #) -> () | ||
foo a b c = () | ||
</code></pre> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
|
||
</div> | ||
</details> | ||
|
||
|
||
|
||
</main> | ||
|
||
<footer> | ||
<p class="HF foot"> | ||
This site is a project of <a href="https://haskell.foundation" target="_blank" rel="noopener noreferrer">The | ||
Haskell Foundation</a>. | ||
</p> | ||
<p class="shoutout foot"> | ||
Site proudly generated by | ||
<a href="http://jaspervdj.be/hakyll" target="_blank" rel="noopener noreferrer">Hakyll</a> | ||
</p> | ||
</footer> | ||
|
||
<script>document.querySelectorAll('code.language-haskell').forEach(el => { | ||
hljs.highlightElement(el); | ||
});</script> | ||
</body> | ||
|
||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module StrictField where | ||
|
||
data Foo = MkFoo !Int Int | ||
|
||
foo :: Foo -> Foo -> () | ||
foo !a (MkFoo b !c) = () |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module StrictField where | ||
|
||
data Foo = MkFoo !Int Int | ||
|
||
foo :: Foo -> Foo -> () | ||
foo !a (MkFoo !b !c) = () |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
<h2 id="warning-message">Warning message</h2> | ||
<pre><code>UnliftedTypes.hs:17:6: warning: [-Wredundant-bang-patterns] | ||
Pattern match has redundant bang | ||
In an equation for ‘foo’: foo a = ... | ||
| | ||
17 | foo !a !b !c = () | ||
| ^ </code></pre> | ||
<h2 id="explanation">Explanation</h2> | ||
<p>Haskell allows a user to annotate fields of a datatype as strict, by prepending | ||
their type with an exclamation mark. | ||
Pattern matching on such a constructor forces it to WHNF, but this also automatically | ||
forces any strict fields to evaluate to WHNF as well. | ||
Thus, a Bang Pattern has no effect on a strict field.</p> | ||
|
||
<pre class="filename">StrictField.hs</pre> | ||
<div class="example-container"> | ||
<div class="example"> | ||
<div class="example-inner"> | ||
<div class="example-title">Before</div> | ||
<!-- keep next line as is, i.e., on one line, or the code will not format properly --> | ||
<pre class="example-pre"><code class="language-haskell">module StrictField where | ||
|
||
data Foo = MkFoo !Int Int | ||
|
||
foo :: Foo -> Foo -> () | ||
foo !a (MkFoo !b !c) = () | ||
</code></pre> | ||
</div> | ||
</div> | ||
<div class="example"> | ||
<div class="example-inner"> | ||
<div class="example-title">After</div> | ||
<!-- keep next line as is, i.e., on one line, or the code will not format propertly --> | ||
<pre class="example-pre"><code class="language-haskell">module StrictField where | ||
|
||
data Foo = MkFoo !Int Int | ||
|
||
foo :: Foo -> Foo -> () | ||
foo !a (MkFoo b !c) = () | ||
</code></pre> | ||
</div> | ||
</div> | ||
</div> | ||
|
Oops, something went wrong.