This class effectively gives us a way to generate a value of
f
a based on an
i a, for
Tensor t i.
Having this ability makes a lot of interesting functions possible when
used with
biretract from
SemigroupIn that weren't
possible without it: it gives us a "base case" for recursion in a lot
of cases.
Essentially, we get an
i ~> f,
pureT, where we can
introduce an
f a as long as we have an
i a.
Formally, if we have
Tensor t i, we are enriching the
category of endofunctors with monoid structure, turning it into a
monoidal category. Different choices of
t give different
monoidal categories.
A functor
f is known as a "monoid in the (monoidal) category
of endofunctors on
t" if we can
biretract:
t f f ~> f
and also
pureT:
i ~> f
This gives us a few interesting results in category theory, which you
can stil reading about if you don't care:
- All functors are monoids in the monoidal category on
:+:
- The class of functors that are monoids in the monoidal category on
:*: is exactly the functors that are instances of
Plus.
- The class of functors that are monoids in the monoidal category on
Day is exactly the functors that are instances of
Applicative.
- The class of functors that are monoids in the monoidal category on
Comp is exactly the functors that are instances of
Monad.
This is the meaning behind the common adage, "monads are just monoids
in the category of endofunctors". It means that if you enrich the
category of endofunctors to be monoidal with
Comp, then the
class of functors that are monoids in that monoidal category are
exactly what monads are. However, the adage is a little misleading:
there are many other ways to enrich the category of endofunctors to be
monoidal, and
Comp is just one of them. Similarly, the class of
functors that are monoids in the category of endofunctors enriched by
Day are
Applicative.
Note that instances of this class are
intended to be written
with
t and
i to be fixed type constructors, and
f to be allowed to vary freely:
instance Monad f => MonoidIn Comp Identity f
Any other sort of instance and it's easy to run into problems with
type inference. If you want to write an instance that's "polymorphic"
on tensor choice, use the
WrapHBF and
WrapF newtype
wrappers over type variables, where the third argument also uses a
type constructor:
instance MonoidIn (WrapHBF t) (WrapF i) (MyFunctor t i)
This will prevent problems with overloaded instances.