Since every Applicative Functor is a Functor, fmap
can always be used on it; thus the essence of Applicative is the pairing of carried contents, as well as the ability to create it:
class Functor f => PairingFunctor f where
funit :: f () -- create a context, carrying nothing of import
fpair :: (f a,f b) -> f (a,b) -- collapse a pair of contexts into a pair-carrying context
This class is isomorphic to Applicative
.
pure a = const a <$> funit = a <$ funit
fa <*> fb = (\(a,b) -> a b) <$> fpair (fa, fb) = uncurry ($) <$> fpair (fa, fb)
Conversely,
funit = pure ()
fpair (fa, fb) = (,) <$> fa <*> fb