Search code examples
haskellghcderivingderivingvia

Why is there no `-XDeriveApplicative` extension?


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)?


Solution

  • 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.