Justin Le recently put out a two-part series on “Enhancing Functor Structures Step-By-Step” (Part 1, Part 2). In the footnotes of Part 2, he mentions there’s no combined `Applicative`

/`Divisible`

class:

```
class DivisibleApplicative f where
conquerpure :: a -> f a
divideAp :: (a -> (b, c)) -> (b -> c -> a) -> f b -> f c -> f a
```

Let’s see if we can build one.

In Ed Kmett’s 2015 talk, Discrimination is Wrong: Improving Productivity, he shows the similarities between `Applicative`

/`Alternative`

/`Divisible`

/`Decidable`

using Day convolution, where `*1`

and `*2`

are two different tensor products:

```
-- Adapted from the slide at 18:10 or so in the video
data Day f g a where
Day :: ((a *1 b) -> c) *2 f a *2 g b -> Day f g c
data ContraDay f g a where
ContraDay :: (c -> (a *1 b)) *2 f a *2 g b -> ContraDay f g c
```

Then:

`Applicative`

comes from covariant Day convolution with`*1 = (,)`

and`*2 = (,)`

`Alternative`

comes from covariant Day convolution with`*1 = Either`

and`*2 = (,)`

`Divisible`

comes from contravariant Day convolution with`*1 = (,)`

and`*2 = (,)`

`Decidable`

comes from contravariant Day convolution with`*1 = Either`

and`*2 = (,)`

`pure`

, `empty`

, and `conquer`

can be rearranged so that they each mention the unit of their `*1`

tensor, and then lined up to reveal a pattern:

```
-- At 25:00 or so in the video
pureish :: Applicative f => (() -> a) -> f a
emptyish :: Alternative f => (Void -> a) -> f a
conquerish :: Divisible f => (a -> ()) -> f a
lose :: Decidable f => (a -> Void) -> f a
```

And you can do the same with the “`liftA2`

-equivalent” of each class:

```
-- Not in the video
liftA2 (,) :: Applicative f => f a -> f b -> f (a, b)
\l r -> Left <$> l <|> Right <$> r :: Alternative f => f a -> f b -> f (Either a b)
divided :: Divisible f => f a -> f b -> f (a, b)
chosen :: Decidable f => f a -> f b -> f (Either a b)
```

Bartosz Milewski has a 2018 blogpost where he stands up a class `Monoidal`

and claims that it’s equivalent to `Applicative`

:

That claim doesn’t sound quite right to me: without a `Functor`

superclass constraint, any `Divisible`

can also be written in terms of this `Monoidal`

class. If we choose other biendofunctors inside `f`

, we can abstract over `Alternative`

and `Decidable`

too:

```
{-# LANGUAGE FlexibleContexts, FunctionalDependencies #-}
import qualified Control.Category.Monoidal as C -- From `categories`
class C.Monoidal (->) p => Monoidal f p | f -> p where
unit :: f (C.Id (->) p)
mult :: f a -> f b -> f (p a b)
lunit :: f (C.Id (->) p) -> f a -> f a
runit :: f a -> f (C.Id (->) p) -> f a
```

You can define `newtype`

wrappers which show that if you have any of `Applicative`

/`Alternative`

/`Divisible`

/`Decidable`

, you can get a `Monoidal`

instance.

An interesting application is bidirectional parsing/printing. The following type cannot have `Functor`

/`Contravariant`

/`Applicative`

/`Alternative`

/`Divisible`

/`Decidable`

instances, but can have `Invariant`

and `Monoidal`

instances:

```
-- With Functor/Applicative/Alternative instances
data Parser a
-- With Contravariant/Divisible/Decidable instances
data PrettyPrinter a
data Bidirectional a = B (Parser a) (PrettyPrinter a)
```

Operations built using `Monoidal`

end up putting `(,)`

s and `Either`

s all over the place, so `generics-eot`

turns out to be a pretty neat way of building `Bidirectional`

s for any data type with a `Generic`

instance.

I have a library implementing this machinery about 80% ready to publish to Hackage, but I first want to get the core abstraction right. The questions I want to answer:

What is this

`Monoidal`

class, exactly? I*think*the instances are lax monoidal functors`f`

from (**Hask**,`p`

,`C.Id (->) p`

) to either (**Hask**,`(,)`

,`()`

) or (**Hask**^{op},`(,)`

,`()`

). Is`Monoidal`

a good name for this class? Is there a better one?I don’t especially like the fundep

`| f -> p`

, but if I drop it GHC complains. Is there a better way?For types with a

`Monoidal`

instance but no`Applicative`

/`Alternative`

/`Divisible`

/`Decidable`

instance, we can’t`fmap`

nor`contramap`

. The`Bidirectional`

type above would admit an`Invariant`

instance, and I feel like most practical uses of this class will be for types which have`Invariant`

instances. Maybe I should just make`Invariant f`

a superclass of`Monoidal f p`

, which would let me default the`lunit`

and`runit`

methods?The

`Monoidal`

class feels stuck in-between committing to Haskell-as-it-is-used and trying to be quite general.`Control.Category.Monoidal`

is a little awkward to use because there aren’t many instances, and it’s generalised across other types of arrows so we have to pass in`(->)`

explicitly. The class`Assoc`

from the`assoc`

package is almost what we want, but doesn’t have a subclass with unitors. If it did, we could define`Monoidal`

in terms of that, which is probably more practical.If I break off a unitless superclass from

`Monoidal`

(like the classes you find in`semigroupoids`

), I*think*the result is a lax semi-monoidal functor, which could then abstract over`Apply`

and`Alt`

from`semigroupoids`

, as well as`Divise`

and`Decide`

from`functor-combinators`

. That seems nifty; maybe I should do that before an initial release?

If you have thoughts about this, please share them on the reddit thread.

**Update (2020-08-23):** After some excellent comments on reddit, I have decided not to push a monoidal functors library to Hackage, for a few reasons:

It appears that there isn’t a lot of other uses for

`Invariant`

functors, and requiring them here is a bit of a kludge.Bidirectional parsing/printing can be done with

`Profunctor`

s, where you work with a`data PrinterParser a b = PrinterParser (PrettyPrinter a) (Parser b)`

. The`product-profunctors`

package provides`ProductProfunctor`

and`SumProfunctor`

classes.There is also the work of Xia, Orchard, and Wang on composing bidirectional programs monadically. This work uses a profunctor

`p a b`

, where`p a`

is also a`Monad`

.If you have an existing

`Divisible f`

and an`Applicative g`

, you can assemble such a`Profunctor`

via`Product (Clown f) (Joker g)`

.

Asad Saeeduddin already has a more mature and more mathematically-thorough library of monoidal functors. It is not yet on Hackage, but includes

`Semigroupal`

functors, support for varying both the input and output tensors and support for oplax (semi-)monoidal functors as well (going e.g.,`f (a, b) -> (f a, f b)`

).