summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorRyanGlScott <ryan.gl.scott@gmail.com>2016-02-17 12:06:17 +0100
committerBen Gamari <ben@smart-cactus.org>2016-02-17 21:04:31 +0100
commita82956df5b34175410e0feb9e2febe7d39b60b49 (patch)
treeac6a1ab07f37cc7e95a6d92b833d165ff35ea3a2 /docs
parent67d22261da840c5ba90414496457b583df0a3911 (diff)
downloadhaskell-a82956df5b34175410e0feb9e2febe7d39b60b49.tar.gz
Remove superfluous code when deriving Foldable/Traversable
Currently, `-XDeriveFoldable` and `-XDeriveTraversable` generate unnecessary `mempty` and `pure` expressions when it traverses of an argument of a constructor whose type does not mention the last type parameter. Not only is this inefficient, but it prevents `Traversable` from being derivable for datatypes with unlifted arguments (see Trac #11174). The solution to this problem is to adopt a slight change to the algorithms for `-XDeriveFoldable` and `-XDeriveTraversable`, which is described in [this wiki page](https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/DeriveFu nctor#Proposal:alternativestrategyforderivingFoldableandTraversable). The wiki page also describes why we don't apply the same changes to the algorithm for `-XDeriveFunctor`. This is techincally a breaking change for users of `-XDeriveFoldable` and `-XDeriveTraversable`, since if someone was using a law-breaking `Monoid` instance with a derived `Foldable` instance (i.e., one where `x <> mempty` does not equal `x`) or a law-breaking `Applicative` instance with a derived `Traversable` instance, then the new generated code could result in different behavior. I suspect the number of scenarios like this is very small, and the onus really should be on those users to fix up their `Monoid`/`Applicative` instances. Fixes #11174. Test Plan: ./validate Reviewers: hvr, simonpj, austin, bgamari Reviewed By: simonpj, bgamari Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D1908 GHC Trac Issues: #11174
Diffstat (limited to 'docs')
-rw-r--r--docs/users_guide/8.0.1-notes.rst5
-rw-r--r--docs/users_guide/glasgow_exts.rst24
2 files changed, 15 insertions, 14 deletions
diff --git a/docs/users_guide/8.0.1-notes.rst b/docs/users_guide/8.0.1-notes.rst
index 5bc3e597ba..7a7bd25f1d 100644
--- a/docs/users_guide/8.0.1-notes.rst
+++ b/docs/users_guide/8.0.1-notes.rst
@@ -192,7 +192,10 @@ Language
In previous versions of GHC, this required a workaround via an
explicit export list in ``Bar``.
-
+- :ghc-flag:`-XDeriveFoldable` and :ghc-flag:`-XDeriveTraversable` now
+ generate code without superfluous ``mempty`` or ``pure`` expressions. As a
+ result, :ghc-flag:`-XDeriveTraversable` now works on datatypes that contain
+ arguments which have unlifted types.
Compiler
~~~~~~~~
diff --git a/docs/users_guide/glasgow_exts.rst b/docs/users_guide/glasgow_exts.rst
index dfa8669a34..593124d257 100644
--- a/docs/users_guide/glasgow_exts.rst
+++ b/docs/users_guide/glasgow_exts.rst
@@ -3515,8 +3515,11 @@ would generate the following instance::
The algorithm for :ghc-flag:`-XDeriveFoldable` is adapted from the :ghc-flag:`-XDeriveFunctor`
algorithm, but it generates definitions for ``foldMap`` and ``foldr`` instead
-of ``fmap``. Here are the differences between the generated code in each
-extension:
+of ``fmap``. In addition, :ghc-flag:`-XDeriveFoldable` filters out all
+constructor arguments on the RHS expression whose types do not mention the last
+type parameter, since those arguments do not need to be folded over.
+
+Here are the differences between the generated code in each extension:
#. When a bare type variable ``a`` is encountered, :ghc-flag:`-XDeriveFunctor` would
generate ``f a`` for an ``fmap`` definition. :ghc-flag:`-XDeriveFoldable` would
@@ -3527,10 +3530,6 @@ extension:
``fmap`` on it. Similarly, :ghc-flag:`-XDeriveFoldable` would recursively call
``foldr`` and ``foldMap``.
-#. When a type that does not mention ``a`` is encountered, :ghc-flag:`-XDeriveFunctor`
- leaves it alone. On the other hand, :ghc-flag:`-XDeriveFoldable` would generate
- ``z`` (the state value) for ``foldr`` and ``mempty`` for ``foldMap``.
-
#. :ghc-flag:`-XDeriveFunctor` puts everything back together again at the end by
invoking the constructor. :ghc-flag:`-XDeriveFoldable`, however, builds up a value
of some type. For ``foldr``, this is accomplished by chaining applications
@@ -3596,12 +3595,15 @@ would generate the following ``Traversable`` instance::
instance Traversable Example where
traverse f (Ex a1 a2 a3 a4)
- = fmap Ex (f a1) <*> traverse f a3
+ = fmap (\b1 b3 -> Ex b1 a2 b3 a4) (f a1) <*> traverse f a3
The algorithm for :ghc-flag:`-XDeriveTraversable` is adapted from the
:ghc-flag:`-XDeriveFunctor` algorithm, but it generates a definition for ``traverse``
-instead of ``fmap``. Here are the differences between the generated code in
-each extension:
+instead of ``fmap``. In addition, :ghc-flag:`-XDeriveTraversable` filters out
+all constructor arguments on the RHS expression whose types do not mention the
+last type parameter, since those arguments do not produce any effects in a
+traversal. Here are the differences between the generated code in each
+extension:
#. When a bare type variable ``a`` is encountered, both :ghc-flag:`-XDeriveFunctor` and
:ghc-flag:`-XDeriveTraversable` would generate ``f a`` for an ``fmap`` and
@@ -3612,10 +3614,6 @@ each extension:
``fmap`` on it. Similarly, :ghc-flag:`-XDeriveTraversable` would recursively call
``traverse``.
-#. When a type that does not mention ``a`` is encountered, :ghc-flag:`-XDeriveFunctor`
- leaves it alone. On the other hand, :ghc-flag:`-XDeriveTraversable` would call
- ``pure`` on the value of that type.
-
#. :ghc-flag:`-XDeriveFunctor` puts everything back together again at the end by
invoking the constructor. :ghc-flag:`-XDeriveTraversable` does something similar,
but it works in an ``Applicative`` context by chaining everything together