X Is Simply A Monoid In The Category Of Y-functor Part 2
Monads as monoids in the category of endofunctors are passé. They’re Banksy. They’re mid-2000’s The Killers. Interesting and exciting when we first discovered them, now trite and only to be enjoyed ironically.
Applicative as monoids in the category of endofunctors though. These are Flying Lotus. They are Finnegan’s Wake. They are the Fluxus movement. They are all things you say you understand but deep down, we know it’s a trendy facade.
First, a flying tour of an applicative functor. As the name implies, extend these upon a functor. If we map a function of greater than one arguements over a functor, we get a partially applied function inside the functor:
We’ve got no easy way to apply this, and none that work for all cases. Enter applicatives. The <*>
operator lets us apply a functor function on the left over a functor value, e.g:
Applicatives form what is known as a strong lax monoidal functor. Don’t pout, look on the bright side - we know what half of those words mean. Let’s start with the easy part; all applicatives in Haskell are strong. The strength is defined by a natural transformation of stA,B:A⊗F B→F(A⊗B) , in Haskell that is:
A lax monoidal functor is a functor between two categories that preserves the monoid each form together with a natural transformation:
We’re putting together all the puzzle pieces to create a monoid in the category of endofunctors, but there will need to be a different kind of tensor - Monads compose, for Applicatives we’ll need to use what is known as the Day convolution. Contrary to Notions of Computation as Monoids, I’ve curried the function and had to make the existential quantification explicit:
It can be thought of as such: a box f
of b
’s, a box g
of c
’s, with a function that takes b
and c
and returns some a
.
With the existential quantifications, we can’t derive functor with GHC but it’s trivial enough.
instance (Functor f, Functor g) => Functor (Day f g) where
fmap f (Day x y g) = Day x y $ \b c -> f (g b c)
Our identity remains the same but, as mentioned previously, the tensor has now changed. Our new tensor is thus:
class Functor m => Monoid' m where
unit :: a -> m a
tensor :: Day m m a -> m a
instance Applicative f => Monoid' (App f) where
unit (Identity x) = F $ pure x
tensor (Day fb gc bca) = F (fmap bca (unF fb) <*> unF gc)
The tensor is nothing more than a generalisation of liftA2
, lifting binary functions over applicatives.