19

Recently I've been dusting off my knowledge on how Monads work. I've also been introduced to the concept of a 'Comonad', which is described as the inverse dual of a monad. However, I am impossible to wrap my head around it.

To understand Monads, I made the own analogy for myself:

Monads can be seen as 'a blueprint to build conveyor belts of expressions'.

To define a new Monad(a new kind of conveyor-belt system) you need to define:

  1. A way to put something on a conveyor belt, e.g. 'start' a conveyor belt. (Known as unit or return)
  2. A way to connect a machine (an expression) that will be part of a conveyor belt to a conveyor belt. (Known as join or bind or >>=).

(There is a third operation that takes the current conveyor belt, throws its contents away and starts a new conveyor belt known as >>, but it is used very rarely.)

For the machines and conveyors to work properly together, you will need to make sure that:

  1. If you put something on a conveyor belt and pass it through a machine, the output should be the same as when you pass it through the machine manually. (Left Identity)
  2. If you want to put a conveyor-belt in-between an already existing conveyor belt, you should not end up with a conveyor belt that has a conveyor belt on top, but rather a single, longer conveyor belt. (Right Identity)
  3. It should not matter for the output if you manually use machine A, and then pass the result through the conveyor-connected B-C, or if you use conveyor-connected A-B and then pass the result manually through C. In other words: ((a >>= b) >>= c) should be the same as (a >>= (b >>= c)) (Associativity)

The most simple conveyor-belt would be the one that just takes the input and always continues on to the next expression. This is what a 'pipeline' is.

Another possibility, is to only let it go through the next machine if some condition is met for the value. This means that if at some of the expressions in-between, the value changes to something that is no longer allowed, then the rest of the expressions will be skipped. This is what the 'Maybe' monad does in Haskell.

You can also do other fancy conditional copy/change rules on the values before or after you pass them to a machine. An example: Parsers (Here, if an expression returns a 'failure' result, the value from before the expression is used as output).

Of course the analogy is not perfect, but I hope it gives an okay representation of how monads work.

However, I am having a lot of trouble to turn this analogy on its head to understand Comonads. I know from the small amounts of information I've found on the internet that a Comonad defines:

  • extract, which is sort of the reverse of return, that is, it takes a value out of a Comonad.
  • duplicate, which is sort of the inverse of join, that is, it creates two Comonads from a single one.

But how can a Comonad be instantiated if we're only able to extract from them or duplicate them? And how can they actually be used? I've seen this very amazing project and the talk about it (which I unfortunately understood very little of), but I am not sure what part of the functionality is provided by a Comonad exactly.

What is a Comonad? What are they useful for? How can they be used? Are they edible?

Qqwy
  • 4,709
  • 4
  • 31
  • 45
  • 3
    "how can a Comonad be instantiated if we're only able to extract from them or duplicate them?" - I'll answer your question with a question: _how can a Monad be consumed if you're only able to lift values into them and sequence computations?_ – Benjamin Hodgson Jun 16 '16 at 13:29
  • @BenjaminHodgson Wow! Very interesting question! Hmm... we don't, really, right? Instead, to 'consume' a Monad, you add a machine to the end of the conveyor belt that does something useful with the internal representation (which can be thought of as 'consuming' in some way), outputting 'nothing' back on the conveyor belt. Is this correct? – Qqwy Jun 16 '16 at 13:39
  • Hmmm... Above is not the whole story. It is true for monads like 'IO'. Of course, there also is the case where you simply use the wrapped value, such as with Haskell's Maybe Monad (which is either `Nothing` or `Just some_successful_outcome`). – Qqwy Jun 16 '16 at 13:41
  • 1
    The "machine at the end of the conveyor belt" (aside: I don't find analogies all that helpful when talking about monads) of the `IO` monad is the Haskell runtime system, which invokes `main`. There's also `unsafePerformIO`, of course. If you want to think of the `Maybe` monad as having a "machine at the end of the conveyor belt" you can use [`maybe`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Prelude.html#v:maybe). – Benjamin Hodgson Jun 16 '16 at 14:00
  • 1
    But, turning your explanation around, when you want to produce a comonadic value at the start of a chain of `cobind` applications, there must be some function which does something useful with the internal representation of your comonad. – Benjamin Hodgson Jun 16 '16 at 14:01
  • 2
    specific instance of comonad or monad can clearly have more functionality than required just to implement the typeclasses – jk. Jun 16 '16 at 14:13
  • 2
    Not that this is going to be helpful if you don't approach this question from the category-theoretical / mathematical side, but I wanted to point out that a comonad is not the inverse but rather the *dual* of a monad. – Jörg W Mittag Jun 16 '16 at 16:27
  • I know this is late to the game but I wanted to point out that `join` is __not__ the same as `bind`/`>>=` - it's an additional operation built on top of `bind`. Thus `duplicate` is still the "inverse" of `join` but it is not the inverse of `bind`. I'm still wrapping my own head around all this stuff but I hope that at least removes one source of confusion! – retnuH Jun 20 '18 at 19:25
  • 1
    @retnuH You can build `join` from `bind` and `return`, but you can also build `bind` from `join` and `return`, so you only need one of `bind` or `join` to build a Monad. – Qqwy Jun 21 '18 at 10:11
  • Good point; just wanted to clarify because the original post can read like they are all the same thing, rather than two sides of the same coin. `duplicate` makes sense as a dual of `join`, but not so much as a dual of `bind`/`>>=`. – retnuH Jun 22 '18 at 10:59
  • From my little understanding, a comonad is a [Rube Goldberg machine](https://en.wikipedia.org/wiki/Rube_Goldberg_machine) to do post-docs: http://www.willamette.edu/~fruehr/haskell/evolution.html ...sorry, I couldn't resist it. – dagnelies Jun 20 '16 at 12:44

0 Answers0