Make liftA2 a method of Applicative
Some functors support implementations of liftA2
that are considerably faster than the usual definition. Furthermore, some people see liftA2
as more intuitive and fundamental to the idea of Applicative
than <*>
is.
This has been discussed on the libraries list in https://mail.haskell.org/pipermail/libraries/2017-January/027579.html and (as an official proposal) in https://mail.haskell.org/pipermail/libraries/2017-January/027612.html. All who expressed an opinion favored the proposal. One (David Menendez) specified that his support was weak. The others (Conal Elliott, Kris Nuttycombe, Wren Romano, Bardur Arantsson, and Mario Blažević) either supported the proposal strongly or merely indicated they were "+1". Conal Elliott wrote: [[BR]] [[BR]]
+1.
I also sometimes define a specialized
liftA2
and then use it to define(<*>)
, which then gets used to define the realliftA2
.I think of
liftA2
as playing a role similar tofoldMap
andtraverse
, while(<*>)
corresponds tofold
andsequenceA
. The first three self-compose nicely:liftA2.liftA2.liftA2
,foldMap.foldMap.foldMap
, andtraverse.traverse.traverse
. With functor composition, it's so much nicer to writeliftA2.liftA2
(in the style ofFunctor
,Foldable
, andTraversable
) rather thanliftA2 (<*>)
.
[[BR]]
Wren Romano wrote [[BR]] [[BR]]
I'm also all for adding liftA2 to the class and have noticed this inefficiency/asymmetry when working on the class hierarchies for other languages
[[BR]]
Kris NuttyCombe wrote [[BR]] [[BR]]
I'm in favor of this change. From my perspecive, liftA2 is actually the fundamental Applicative operation, an <*> is merely a convenient isomorphism. When I'm teaching, showing the symmetry between the following always seems to help students:
fmap :: (a -> b) -> f a -> f b liftA2 :: (a -> b -> c) -> f a -> f b -> f c flip (>>=) :: (a -> f b) -> f a -> f b
<*> is obviously exceptionally useful in practice. But liftA2 seems like the more essential shape of that operation.