Applicative functors are well-known and well-loved among Haskellers, for their ability to apply functions in an effectful context.
In category-theoretic terms, it can be shown that the methods of Applicative
:
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
are equivalent to having a Functor f
with the operations:
unit :: f ()
(**) :: (f a, f b) -> f (a,b)
the idea being that to write pure
you just replace the ()
in unit
with the given value, and to write (<*>)
you squish the function and argument into a tuple and then map a suitable application function over it.
Moreover, this correspondence turns the Applicative
laws into natural monoidal-ish laws about unit
and (**)
, so in fact an applicative functor is precisely what a category theorist would call a lax monoidal functor (lax because (**)
is merely a natural transformation and not an isomorphism).
Okay, fine, great. This much is well-known. But that's only one family of lax monoidal functors – those respecting the monoidal structure of the product. A lax monoidal functor involves two choices of monoidal structure, in the source and destination: here's what you get if you turn product into sum:
class PtS f where
unit :: f Void
(**) :: f a -> f b -> f (Either a b)
-- some example instances
instance PtS Maybe where
unit = Nothing
Nothing ** Nothing = Nothing
Just a ** Nothing = Just (Left a)
Nothing ** Just b = Just (Right b)
Just a ** Just b = Just (Left a) -- ick, but it does satisfy the laws
instance PtS [] where
unit = []
xs ** ys = map Left xs ++ map Right ys
It seems like turning sum into other monoidal structures is made less interesting by unit :: Void -> f Void
being uniquely determined, so you really have more of a semigroup going on. But still:
- Are other lax monoidal functors like the above studied or useful?
- Is there a neat alternative presentation for them like the
Applicative
one?