Hrm. It's a shame that supporting this map/coerce RULE causes such pain.
This makes me wonder: can we get rid of this RULE? Eric Mertens pointed out a trick [1] that's used in the profunctors library to make mapping coerce over certain Profunctors more efficient. To adapt this trick for Functor, we'd need to add another class method:
class Functor f where
fmap :: (a -> b) -> f a -> f b
(<#>) :: Coercible a b => (a -> b) -> f a -> f b
(<#>) = \f -> \p -> p `seq` fmap f p
Now, when implementing Functor instances, if we are working with a datatype whose role is representational or phantom, we can make (<#>) really fast:
data List a = Nil | Cons a (List a)
instance Functor List where
fmap = ...
(<#>) = coerce
Now, instead of relying on (map MkNewtype Nil) to rewrite to Nil, we can just use (MkNewtype <#> Nil)! No map/coerce RULE necessary :)
OK, I realize that suggesting that we remove the RULE is perhaps a touch too far. But it does sting that we have to pay hefty compilation penalties because of its existence...
Ryan S.
-----