
<p>In <a href="https://stackoverflow.com/a/23316850/1333025">this post on SO</a> I found an interesting answer - <a href="https://fplab.bitbucket.io/posts/2007-07-08-decisive-functors.html" rel="nofollow noreferrer">decisive functors</a>. If we replace <code>()</code> by <code>Void</code>, <code>(,)</code> by <code>Either</code> <em>and</em> reverse the arrows, we get:</p>
<pre><code>class Functor f =&gt; Decisive f where
    nogood :: f Void -&gt; Void
    orwell :: f (Either s t) -&gt; Either (f s) (f t)
</code></pre>
<p>The blog post also gives some laws that decisive functors adhere to.</p>
<p>And, every <code>Comonad</code> is also <code>Decisive</code>:</p>
<pre><code>nogoodW :: (Comonad f) =&gt; f Void -&gt; Void
nogoodW = counit

orwellW :: (Comonad f) =&gt; f (Either s t) -&gt; Either (f s) (f t)
orwellW story = case counit story of
                      Left s  -&gt; fmap (either id (const s)) story
                      Right t -&gt; fmap (either (const t) id) story 
</code></pre>
<p>So decisive functors fit in between functors and comonads, just as applicative functors fit in between functors and monads.</p>

CC BY-SA 4.0
2014-04-27T07:22:31.747Z
2023-08-28T14:21:18.100Z
2023-08-28T14:21:18.100Z
Petr
<p><a href="http://www.soi.city.ac.uk/~ross/papers/Applicative.pdf" rel="nofollow">McBride and Patterson</a> (Section 7) show that an applicative functor, also known as an idiom, is a <em>strong lax monoidal functor</em>. You are looking for a <em>strong colax monoidal functor</em> also known as an <em>strong oplax monoidal functor</em>.  As mentioned in a comment, an oplax monoidal functor is a lax monoidal functor between the opposite categories, which ends up being a comonoidal version of a lax monoidal functor. </p>

<p>Draw the diagrams, reverse the arrows!</p>

<p>I'd have to spend a bit of time working out the details to see which it is, and to translate it into a functional programming notion.</p>

CC BY-SA 3.0
2013-01-28T20:13:02.107Z
For some reason the standard term seems to be "oplax monoidal functor". The idea is a lax monoidal functor between the opposite categories, which ends up being a comonoidal version of a lax monoidal functor. Using "colax comonoidal" is either redundant or equivalent to "lax monoidal".
C. A. McCann
CC BY-SA 3.0
2013-01-28T21:08:54.940Z
I overdid the "co"-ing. I'll fix my answer.
Dave Clarke
CC BY-SA 3.0
2013-01-27T12:23:43.760Z
2014-04-27T10:12:18.897Z
2014-04-27T10:12:18.897Z
Dave Clarke
<p>First of all:</p>

<blockquote>
  <p>Any monad is also an applicative functor and any applicative functor is a functor.</p>
</blockquote>

<p>This is true in the context of Haskell, but (reading <code>Applicative</code> as "strong lax monoidal functor") not in general, for the rather trivial reason that you can have "applicative" functors between different monoidal categories, whereas monads (and comonads) are endofunctors.</p>

<p>Further, identifying <code>Applicative</code> with strong lax monoidal functors is slightly misleading, because to justify the name (and the type signature of <code>(&lt;*&gt;)</code>) requires a functor between <a href="http://ncatlab.org/nlab/show/closed+monoidal+category">closed monoidal categories</a> which preserves both the <a href="http://ncatlab.org/nlab/show/monoidal+functor">monoidal structure</a> and the <a href="http://ncatlab.org/nlab/show/closed+functor">internal hom</a>. This could plausibly be called a "lax closed monoidal functor", except that a functor between monoidal closed categories that preserves either property preserves the other in <a href="http://ncatlab.org/nlab/show/currying">the obvious way</a>. Because <code>Applicative</code> describes only endofunctors on <strong>Hask</strong> preserving the monoidal structure of <code>(,)</code>, its instances gain a lot of properties automatically, including their <a href="http://ncatlab.org/nlab/show/tensorial+strength">strength</a>, which can thus be elided.</p>

<p>The apparent connection with <code>Monad</code> is arguably an artifact of the implicit limitations on <code>Applicative</code> causing aspects of their respective monoid structures to coincide, a happy coincidence which unfortunately does not survive dualization.</p>

<p>Just as a comonad on a category $C$ is a monad on $C^{op}$, an <a href="http://ncatlab.org/nlab/show/oplax+monoidal+functor">oplax monoidal functor</a> $C \rightarrow D$ is a lax monoidal functor $C^{op} \rightarrow D^{op}$. But $ \boldsymbol{Hask}^{op}$ is not monoidal <em>closed</em>, and a co-<code>Applicative</code> that doesn't include function application hardly merits the name. Anyway, the result wouldn't be terribly interesting:</p>

<pre><code>class (Functor f) =&gt; CoMonoidal f where
    counit :: f () -&gt; ()
    cozip :: f (a, b) -&gt; (f a, f b)
</code></pre>

<p>We could instead imagine a notion of "colax closed functor", which would look much more like <code>Applicative</code> if it existed. Unfortunately, $\boldsymbol{Hask}^{op}$ is not (to the best of my knowledge) a closed category at all: <code>newtype Op b a = Op (a -&gt; b)</code> in $\boldsymbol{Hask}$ corresponds to morphisms $b \rightarrow a$ in $\boldsymbol{Hask}^{op}$, but <code>Op b a</code> doesn't work as an internal hom there--because the arrows are reversed some sort of co-function would be required instead, which we can't define in general for $\boldsymbol{Hask}$.</p>

<p>If we simply pretend that "colax closed functors" existed for $\boldsymbol{Hask}$, and furthermore worked in the way we'd naively hope they would, a co-<code>Applicative</code> based on that would probably look like this:</p>

<pre><code>class (Functor f) =&gt; CoApplicative f where
    copure :: f a -&gt; a
    coap :: (f a -&gt; f b) -&gt; f (a -&gt; b)
</code></pre>

<p>Adding <code>duplicate :: f a -&gt; f (f a)</code> to <code>copure</code> would produce a comonad (assuming the laws are satisfied), of course. But there's no obvious relationship between <code>coap</code>--whatever it might be--and <code>extend :: (f a -&gt; b) -&gt; f a -&gt; f b</code>. Comparing the types it becomes clear that the dualization is happening in different ways: the comonoidal structures underlying <code>duplicate</code> and <code>cozip</code> have little to do with each other or with <code>coap</code> (which probably doesn't make sense anyway), whereas <code>liftA2 (,)</code> and <code>(&lt;*&gt;)</code> are equivalent and can be derived from <code>join</code>.</p>

<p>Another possible way of dualizing <code>Applicative</code>, which has even less to do with comonads, is to consider contravariant monoidal functors:</p>

<pre><code>class (Contravariant f) =&gt; ContraMonoidal f where
    contraunit :: f a
    contrazip :: f a -&gt; f b -&gt; f (Either a b)
</code></pre>

<p>But this runs afoul of the same issues as above, namely that $\boldsymbol{Hask}^{op}$ is not a closed category. If it were, we would have some type <code>b &lt;~ a</code> such that we could write functions like <code>contracurry :: (Either c b &lt;~ a) -&gt; (c &lt;~ (b &lt;~ a))</code> and <code>contraapply :: b -&gt; Either a (a &lt;~ b)</code> and so on that actually worked as expected.</p>

<p>If memory serves me, the obstacles here are not specific to Haskell, but rather arise from $\boldsymbol{Hask}$ being <a href="http://ncatlab.org/nlab/show/cartesian+closed+category">cartesian closed</a> (up to the usual hand-waving, of course), a property it shares with most typed lambda calculi, so you're not likely to get very far with a <code>CoApplicative</code> in most settings. </p>

<p>However, in a monoidal closed category more hospitable to dualization you might have better luck. In particular, I believe both <code>Kleisli (Cont r)</code> and its opposite category are monoidal closed, so that might be a better context to explore these ideas.</p>

CC BY-SA 3.0
2017-02-21T17:30:08.040Z
Comparing your answer to http://cstheory.stackexchange.com/a/22302/989, it's surprising that you don't dualize products to sums. Of course, you're right that Hask doesn't have categorical sums; but if you're willing to restrict to the category of total programs (like in Agda), let's pretend it's Set for now, that problem disappears. (I'm not saying Set^op is monoidal closed, but I suspect what I'm saying implies it).
Blaisorblade
CC BY-SA 3.0
2013-01-28T20:01:40.100Z
2013-01-28T20:01:40.100Z
C. A. McCann
<p>Any monad is also an applicative functor and any applicative functor is a functor. Also, any comonad is a functor. Is there a similar concept between comonads and functors, something like co-applicative functor, and what are its properties?</p>

<p>\begin{array}{c}
\end{array}
\begin{array}{cc}
\mbox{Functors} &amp; &amp; \mbox{Functors} \\
\uparrow &amp; &amp; \uparrow \\
\mbox{Applicative functors} &amp; &amp; ??? \\
\uparrow &amp; &amp; \uparrow \\
\mbox{Monads} &amp; &amp; \mbox{Comonads} \\
\end{array}</p>

<p><em>Update:</em> I'd be also interested in possible uses of such a concept.</p>

CC BY-SA 3.0
2016-04-09T02:50:34.393Z
Are you sure you weren't looking for Comonads -> ??? -> Cofunctors?
josiah
CC BY-SA 3.0
2016-04-09T11:14:17.980Z
@josiah No, as far as I know, [comonads are functors](https://hackage.haskell.org/package/comonad-5/docs/Control-Comonad.html#t:Comonad), not cofunctors.
Petr
CC BY-SA 4.0
2018-06-07T21:22:35.747Z
Isn't [divisible](http://hackage.haskell.org/package/contravariant-1.4.1/docs/Data-Functor-Contravariant-Divisible.html) that missing piece?
Gus
CC BY-SA 4.0
2021-03-27T09:50:37.613Z
@Petr Yes, comonads are functors, but [cofunctors are functors](https://stackoverflow.com/questions/34732571/why-there-is-no-cofunctor-typeclass-in-haskell).
NJay
<ct.category-theory><monad><applicative><comonad>
Is there a concept of something like co-applicative functors sitting between comonads and functors?
Petr
# Is there a concept of something like co-applicative functors sitting between comonads and functors?

(Asked by: username_0 on 2013-01-27)

Any monad is also an applicative functor and any applicative functor is a functor. Also, any comonad is a functor. Is there a similar concept between comonads and functors, something like co-applicative functor, and what are its properties?

\begin{array}{c}
\end{array}
\begin{array}{cc}
\mbox{Functors} & & \mbox{Functors} \\
\uparrow & & \uparrow \\
\mbox{Applicative functors} & & ??? \\
\uparrow & & \uparrow \\
\mbox{Monads} & & \mbox{Comonads} \\
\end{array}

*Update:* I'd be also interested in possible uses of such a concept.

**Tags:** ct.category-theory, monad, applicative, comonad

> **Comments:**
> **username_1**: Are you sure you weren't looking for Comonads -> ??? -> Cofunctors?  
> **username_0**: @username_1 No, as far as I know, [comonads are functors](https://hackage.haskell.org/package/comonad-5/docs/Control-Comonad.html#t:Comonad), not cofunctors.  
> **username_2**: Isn't [divisible](http://hackage.haskell.org/package/contravariant-1.4.1/docs/Data-Functor-Contravariant-Divisible.html) that missing piece?  
> **username_3**: @username_0 Yes, comonads are functors, but [cofunctors are functors](https://stackoverflow.com/questions/34732571/why-there-is-no-cofunctor-typeclass-in-haskell).  

---

## 3 answers

### Answer by username_5 on 2013-01-28. Score: 21 | Accepted answer

First of all:

> Any monad is also an applicative functor and any applicative functor is a functor.

This is true in the context of Haskell, but (reading `Applicative` as "strong lax monoidal functor") not in general, for the rather trivial reason that you can have "applicative" functors between different monoidal categories, whereas monads (and comonads) are endofunctors.

Further, identifying `Applicative` with strong lax monoidal functors is slightly misleading, because to justify the name (and the type signature of `(<*>)`) requires a functor between [closed monoidal categories](http://ncatlab.org/nlab/show/closed+monoidal+category) which preserves both the [monoidal structure](http://ncatlab.org/nlab/show/monoidal+functor) and the [internal hom](http://ncatlab.org/nlab/show/closed+functor). This could plausibly be called a "lax closed monoidal functor", except that a functor between monoidal closed categories that preserves either property preserves the other in [the obvious way](http://ncatlab.org/nlab/show/currying). Because `Applicative` describes only endofunctors on **Hask** preserving the monoidal structure of `(,)`, its instances gain a lot of properties automatically, including their [strength](http://ncatlab.org/nlab/show/tensorial+strength), which can thus be elided.

The apparent connection with `Monad` is arguably an artifact of the implicit limitations on `Applicative` causing aspects of their respective monoid structures to coincide, a happy coincidence which unfortunately does not survive dualization.

Just as a comonad on a category $C$ is a monad on $C^{op}$, an [oplax monoidal functor](http://ncatlab.org/nlab/show/oplax+monoidal+functor) $C \rightarrow D$ is a lax monoidal functor $C^{op} \rightarrow D^{op}$. But $ \boldsymbol{Hask}^{op}$ is not monoidal *closed*, and a co-`Applicative` that doesn't include function application hardly merits the name. Anyway, the result wouldn't be terribly interesting:

```
class (Functor f) => CoMonoidal f where
    counit :: f () -> ()
    cozip :: f (a, b) -> (f a, f b)

```

We could instead imagine a notion of "colax closed functor", which would look much more like `Applicative` if it existed. Unfortunately, $\boldsymbol{Hask}^{op}$ is not (to the best of my knowledge) a closed category at all: `newtype Op b a = Op (a -> b)` in $\boldsymbol{Hask}$ corresponds to morphisms $b \rightarrow a$ in $\boldsymbol{Hask}^{op}$, but `Op b a` doesn't work as an internal hom there--because the arrows are reversed some sort of co-function would be required instead, which we can't define in general for $\boldsymbol{Hask}$.

If we simply pretend that "colax closed functors" existed for $\boldsymbol{Hask}$, and furthermore worked in the way we'd naively hope they would, a co-`Applicative` based on that would probably look like this:

```
class (Functor f) => CoApplicative f where
    copure :: f a -> a
    coap :: (f a -> f b) -> f (a -> b)

```

Adding `duplicate :: f a -> f (f a)` to `copure` would produce a comonad (assuming the laws are satisfied), of course. But there's no obvious relationship between `coap`--whatever it might be--and `extend :: (f a -> b) -> f a -> f b`. Comparing the types it becomes clear that the dualization is happening in different ways: the comonoidal structures underlying `duplicate` and `cozip` have little to do with each other or with `coap` (which probably doesn't make sense anyway), whereas `liftA2 (,)` and `(<*>)` are equivalent and can be derived from `join`.

Another possible way of dualizing `Applicative`, which has even less to do with comonads, is to consider contravariant monoidal functors:

```
class (Contravariant f) => ContraMonoidal f where
    contraunit :: f a
    contrazip :: f a -> f b -> f (Either a b)

```

But this runs afoul of the same issues as above, namely that $\boldsymbol{Hask}^{op}$ is not a closed category. If it were, we would have some type `b <~ a` such that we could write functions like `contracurry :: (Either c b <~ a) -> (c <~ (b <~ a))` and `contraapply :: b -> Either a (a <~ b)` and so on that actually worked as expected.

If memory serves me, the obstacles here are not specific to Haskell, but rather arise from $\boldsymbol{Hask}$ being [cartesian closed](http://ncatlab.org/nlab/show/cartesian+closed+category) (up to the usual hand-waving, of course), a property it shares with most typed lambda calculi, so you're not likely to get very far with a `CoApplicative` in most settings.

However, in a monoidal closed category more hospitable to dualization you might have better luck. In particular, I believe both `Kleisli (Cont r)` and its opposite category are monoidal closed, so that might be a better context to explore these ideas.

> **Comments:**
> **username_6**: Comparing your answer to http://cstheory.stackexchange.com/a/22302/989, it's surprising that you don't dualize products to sums. Of course, you're right that Hask doesn't have categorical sums; but if you're willing to restrict to the category of total programs (like in Agda), let's pretend it's Set for now, that problem disappears. (I'm not saying Set^op is monoidal closed, but I suspect what I'm saying implies it).  

---

### Answer by username_0 on 2014-04-27. Score: 11

In [this post on SO](https://stackoverflow.com/a/23316850/1333025) I found an interesting answer - [decisive functors](https://fplab.bitbucket.io/posts/2007-07-08-decisive-functors.html). If we replace `()` by `Void`, `(,)` by `Either` *and* reverse the arrows, we get:

```
class Functor f => Decisive f where
    nogood :: f Void -> Void
    orwell :: f (Either s t) -> Either (f s) (f t)

```

The blog post also gives some laws that decisive functors adhere to.

And, every `Comonad` is also `Decisive`:

```
nogoodW :: (Comonad f) => f Void -> Void
nogoodW = counit

orwellW :: (Comonad f) => f (Either s t) -> Either (f s) (f t)
orwellW story = case counit story of
                      Left s  -> fmap (either id (const s)) story
                      Right t -> fmap (either (const t) id) story 

```

So decisive functors fit in between functors and comonads, just as applicative functors fit in between functors and monads.


---

### Answer by username_4 on 2013-01-27. Score: 6

[McBride and Patterson](http://www.soi.city.ac.uk/~ross/papers/Applicative.pdf) (Section 7) show that an applicative functor, also known as an idiom, is a *strong lax monoidal functor*. You are looking for a *strong colax monoidal functor* also known as an *strong oplax monoidal functor*. As mentioned in a comment, an oplax monoidal functor is a lax monoidal functor between the opposite categories, which ends up being a comonoidal version of a lax monoidal functor.

Draw the diagrams, reverse the arrows!

I'd have to spend a bit of time working out the details to see which it is, and to translate it into a functional programming notion.

> **Comments:**
> **username_5**: For some reason the standard term seems to be "oplax monoidal functor". The idea is a lax monoidal functor between the opposite categories, which ends up being a comonoidal version of a lax monoidal functor. Using "colax comonoidal" is either redundant or equivalent to "lax monoidal".  
> **username_4**: I overdid the "co"-ing. I'll fix my answer.  

---

