GHC has several useful language extensions for mechanically deriving various common Haskell typeclasses (-XDeriveFunctor
, -XDeriveFoldable
, -XDeriveTraversable
). It seems that Applicative
is another class which is often needed and frequently easily derived. For a simple record containing slots of type a
, e.g.,
data SimpleRecord a = Simple a a a
the Applicative
instance is trivially derived,
instance Applicative SimpleRecord where
pure x = Simple x x x
Simple a1 b1 c1 <*> Simple a2 b2 c2 = Simple (a1 a2) (b1 b2) (c1 c2)
Even in the slightly harder case where some a
values are buried in other applicative functors, e.g.,
data MyRecord f a = MyRecord (f a) a
a reasonable instance is easily written,
instance (Applicative f) => Applicative (MyRecord f) where
pure x = MyRecord (pure x) x
MyRecord a1 b1 <*> MyRecord a2 b2 = MyRecord (a1 <*> a2) (b1 b1)
Why is it that a -XDeriveApplicative
extension implementing these sorts of mechanical instances does not exist? Even the derive
and generic-derive
packages apparently lack Applicative
support. Is there a theoretical issue precluding these instances from being usually valid (beyond those reasons that might also threaten the Functor
, Foldable
, or Traversable
extensions)?
There is at most one instance of Functor
for a given data type that follows the functor laws. For example, map
is the only lawful implementation of fmap
for lists:
fmap id == id
fmap (f . g) == fmap f . fmap g
But there can be more than one law-abiding instance of Applicative
, which isn’t necessarily obvious.
pure id <*> v == v
pure (.) <*> u <*> v <*> w == u <*> (v <*> w)
pure f <*> pure x == pure (f x)
u <*> pure y == pure ($ y) <*> u
For lists, <*>
can behave like \fs xs -> concatMap (\f -> map f xs) fs
or like zipWith ($)
, and it isn’t clear which one the compiler should choose.