Why is there no `

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 , eg,

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, eg,

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.


To echo others, there's no good reason I know of why we can't have -XDeriveApplicative , we simply happen not to. There are typically more than one lawful instance of Foldable and Traversable , and we have a flag to derive those. For a while we had no real good story for traversable laws, but now we have some. Similarly we still have no Foldable laws (but I think we can, see here).

Among the different 'obvious' applicatives, such as forwards and backwards ones (vis a vis <*> itself, and even permuted vis a vis the multiple a in an fa if there are such), then building applicatives as suggested here, with traversal in syntactic order, seems legitimate. However, for recursive types such as lists, or even types with multiple constructors, our choice of valid applicatives blossoms in interesting ways. For listlike regular recursive types, the obvious applicative choice is naturally the "zipLike" once, since it generalizes the nonrecursive case in the natural way, matching structure with structure. For sum types with multiple constructors, the "obvious" choice is much harder to define.

It seems to me that an entirely reasonable derivation of applicative would work as suggested here, in syntactic order on types (including recursive ones) with only one constructor. In cases of multiple constructors, failure seems legitimate.

On the other hand, while Foldable and Traversable seem to come up frequently in their "obvious" forms, its not too clear to me how many times we wish to define "obvious" applicatives, as compared to interesting ones. My intuition tells me this feature would be seldom-exercised, and perhaps simply not frequently useful.

链接地址: http://www.djcxy.com/p/43456.html

上一篇: 为newtype创建MonadBaseControl实例

下一篇: 为什么没有`