Skip to content

<$ 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
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information