After studying monads, a natural topic to turn to next is the comonad. A `Comonad`

is a typeclass with the following methods:

```
trait Comonad[F[_]] extends Functor[F] { self =>
def cobind[A, B](fa: F[A])(f: F[A] => B): F[B]
def copoint[A](p: F[A]): A
}
```

A `Comonad`

must satisfy the laws:

```
cobind(fa)(copoint) === fa // left identity
copoint(cobind(fa)(f)) === f(fa) // right identity
```

For comparison, a `Monad`

looks similar, but with the location of the `F[_]`

reversed:

```
trait Monad[F[_]] extends Functor[F] { self =>
def bind[A,B](fa: F[A])(f: A => F[B]): F[B]
def point[A](a: A): F[A]
}
```

# Example of a Monad and Comonad - `List`

vs `NonEmptyList`

A comonad is best understood via example. Recall that the standard example of a `Monad`

is a list. The `bind`

operation is `flatMap`

:

```
def f(x: Int) = List(x, x+1, x+2)
val a = List(1,2,3)
M.point(a) === List(a)
M.bind(a)(f) === List(List(1,2,3),List(2,3,4), List(4,5,6)).flatten
=== List(1,2,3,2,3,4,4,5,6)
```

(The intermediate step above is displayed for clarity purposes.)

The corresponding example of a `Comonad`

is the `NonEmptyList`

(see code on github) - a list which is guaranteed to have at least one element. The code example above works as follows:

```
def f(x: NonEmptyList[Int]) = x.sum
val a = NonEmptyList(1,2,3)
M.copoint(a) === 1 //take out the first element
M.cobind(a)(f) === NonEmptyList(f(NonEmptyList(1,2,3)), f(NonEmptyList(2,3)), f(NonEmptyList(3)))
=== NonEmptyList(6,5,3)
```

So if we think of `F`

as a container, we can think of `copoint`

as pulling the "first" object out of the container, whereas `cobind`

first "un-flattens" the container and then applies `f`

to each unflattened-element.

## How the laws make life interesting

After playing around a bit, I came up with the following possible implementation of `cobind`

:

```
def pullIn[A](puller: F[_])(pullee: A): F[A] = {
def constFunc(x: Any) = pullee
self.map(puller)(constFunc)
}
def cobindBoring[A, B](fa: F[A])(f: F[A] => B): F[B] = pullIn(fa)(f(fa))
```

This certainly satisfies the type signature. But it's quite **boring** - I can put `cobindBoring`

onto `Functor`

if I want to. Given the fancy name, a `Comonad`

should be more interesting - turns out it is. This boring version of `cobind`

fails the identity law:

```
> cobindBoring(NonEmptyList(1,2,3))(copoint)
NonEmptyList(1,1,1)
```

The result should be `NonEmptyList(1,2,3)`

. So the Comonad laws force our comonads to be interesting - at the very least, we need more than just any old implementation.

# Strong Monads and Costrong Comonads

A strong monad is a monad with an additional function:

```
trait Strong {
def strengthen[A,B](fa: (A,F[B])): F[(A,B)]
}
```

There are 4 laws a Strong Monad must satisfy - the wikipedia page displays them as commutative diagrams. A Costrong Comonad has a complementary definition:

```
trait Costrong {
def costrengthen[A,B](fa: F[Either[A,B]]): Either[A,F[B]]
}
```

What this definition means is that we can co-strengthen the type of `fa`

- it's either an `A`

or else it's an `F[B]`

.

One computational way to interpret this is that the result is `Either`

a result of type `A`

, or else it's an error wrapped in `F[B]`

.

The laws a `Comonad`

must satisfy can be derived by looking at the commutative diagrams on wikipedia and reversing the arrows. When doing this process, the product type `(A,B)`

is replaced by the sum type `Either[A,B]`

. The basic laws of a `CostrongComonad`

are (in addition to the usual `Comonad`

laws):

```
costrengthen(self.map(fb)(x => Right(x): Either[A,B])) === Right(fb)
costrengthen(fab).bimap(x=>x, copoint _) === copoint(fab)
```

There are also a couple of more complicated laws about associativity:

```
costrengthen(fab).bimap(x => x, cojoin _) === costrengthen(self.map(self.cojoin(fab))(costrengthen _))
eassoc(costrengthen(fabc).bimap(a => a, costrengthen _)) === costrengthen( self.map(fabc)(eassoc) )
where
def eassoc[A,B,C](eabc: Either[A,Either[B,C]]): Either[Either[A,B], C] = eabc match {
case Left(a) => Left(Left(a))
case Right(Left(b)) => Left(Right(b))
case Right(Right(c)) => Right(c)
}
```

In one of the few posts I've seen discussing the topic, Edward Kmett shows that in the category `Hask`

, all monads are strong and thus strength is boring. When trying to implement `Costrong`

, I discovered that costrong comonads are also boring.

The reason why is very simple - every `Comonad`

which is also a `Functor`

also satisfies `Costrong`

:

```
implicit def CostrongOfComonad[F[_]](m: Comonad[F]): Costrong[F] = new Costrong {
def costrengthen[A,B](fa: F[Either[A,B]]): Either[A,F[B]] = fa match {
case Left(a) => Left(a)
case Right(b) => Right( m.map(fa)( eab => eab.bimap(_ => b, x => x)) )
}
}
```

In `Hask`

and `Scal`

, of course, every `Comonad`

is also a `Functor`

.

In terms of `NonEmptyList`

, what does this look like?

```
costrengthen(NonEmptyList(Left("oops"), Right(1), Right(2))) === Left("oops")
costrengthen(NonEmptyList(Right(0), Left("oops"), Right(2))) === Right(NonEmptyList(0, 0, 2))
```

It essentially takes a container, looks at the `copoint`

of the container, and replaces all `Left(...)`

instances by the copoint while simply unwrapping the `Right`

elements.

The only properties I used when creating the `Costrong`

object were `Comonad.copoint`

and `Functor.map`

- no additional work is necessary.

`costrengthen`

is not unique

Consider another way of achieving a similar result. Rather than replacing the `Left(...)`

instances with `b`

, we might simply remove them:

However, the `costrengthen`

function is not unique. Another possible definition for `NonEmptyList`

:

```
def costrengthen[A,B](fab: NonEmptyList[Either[A,B]]): Either[A, NonEmptyList[B]] = copoint(fab) match {
case Left(a) => Left(a)
case Right(b) => Right({
val filtered = fab.list.flatMap( _ match {
case Left(_) => List[B]()
case Right(bb) => List(bb)
})
new NonEmptyList(b, filtered.tail)
})
}
```

Running tests shows that this definition also satisfies the `CostrongComonad`

laws.

# Is there some interesting definition of `SemiCostrongComonad`

?

In his post on strength, Edward Kmett poses a different definition of `costrengthen`

. He proposes that if there are *any* left elements in the container, return one of them. Otherwise, return the container after unwrapping the right elements.

I like this definition. But unfortunately it fails the second `CostrongComonad`

law:

```
costrengthen(fab).bimap(x=>x, copoint _) === copoint(fab)
```

The counterexample is easy to see:

```
val x = NonEmptyList(Right(1), Left("oops"))
costrengthen(x).bimap(x => x, copoint _) === Left("oops").bimap(x => x, copoint _)
=== Left("oops")
copoint(x) === Right(1)
```

But here is a puzzle I'm posing: is there an alternate category theoretical construct, which I'll label `SemiCostrongComonad`

, which is more interesting? Some definition which Edward Kmett's proposed `costrengthen`

will actually satisfy?

# Conclusion

In programming languages like Scala and Haskell, `Costrong`

is a boring property for a `Comonad`

to posess. Any `Functor`

, which includes every `Comonad`

satisfies this property. So if we are looking for interesting behaviors to add to a library like scalaz or the Haskell prelude, Costrength is not it.

Anyone who wants to play with these concepts can find my code on github.