<$ is bad in derived functor instances
Functor
deriving derives the definition of fmap
, leaving the definition of <$
to the default. This is quite bad for recursive types:
data Tree a = Bin !(Tree a) a !(Tree a) | Tip deriving Functor
produces
Replace.$fFunctorTree_$c<$ =
\ (@ a_aGl) (@ b_aGm) (eta_aGn :: a_aGl) (eta1_B1 :: Tree b_aGm) ->
Replace.$fFunctorTree_$cfmap
@ b_aGm @ a_aGl (\ _ [Occ=Dead] -> eta_aGn) eta1_B1
Why is this bad? It fills the tree with thunks keeping the original values (which we never use again) alive. What we want to generate is
x <$ Bin l _ r = Bin (x <$ l) x (x <$ r)
When there are other functor types in the constructor, like
| Whatever (Tree (Tree a))
we will need to insert fmap (x <$) t
. The overall shape should be basically the same as fmap
deriving.
Note: there are some types for which we will not realistically be able to derive optimal definitions. In particular, fixed-shape, undecorated types that appear in nested types allow special treatment:
data Pair a = Pair a a deriving Functor
data Tree2 a = Z a | S (Tree2 (Pair a)) deriving Functor
The ideal definition for this type is
x <$ Z _ = Z x
x <$ S t = S (Pair x x <$ t)
but that requires cleverness. We should probably settle for
x <$ Z _ = Z x
x <$ S t = S (fmap (x <$) t)
Trac metadata
Trac field | Value |
---|---|
Version | 8.1 |
Type | Bug |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | Compiler |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | |
Architecture |