Understanding why Zipper is a Comonad

comonad, functional-programming, scala, zipper

Solution

As this question is popping up regularly in the top of the "unanswered" list, let me just copy my comment as an answer here - nothing considerably more constructive has appeared since a year ago anyway.

A `List` can be viewed as a comonad just as well (in multiple ways), while a `Zipper` can be cast as a monad (also in many ways). The difference is in whether you are conceptually focused on "appending" data constructively to a state machine (that's what the `Monad` interface is about), or "extracting" state from it "deconstructively" (that's what the `Comonad` does).

It is not easy to answer the question, stated as "does this understanding make sense", however. In some sense it does, in another it does not.

Problem

This is a follow-up to the answer to my previous question. Suppose I need to map each item `a:A` of `List[A]` to `b:B` with function `def f(a:A, leftNeighbors:List[A]): B` and generate `List[B]`. Obviously I cannot just call `map` on the list but I can use the list zipper. The zipper is a cursor to move around a list. It provides access to the current element (`focus`) and its neighbors. Now I can replace my `f` with `def f'(z:Zipper[A]):B = f(z.focus, z.left)` and pass this new function `f'` to `cobind` method of `Zipper[A]`. The `cobind` works like this: it calls that `f'` with the zipper, then moves the zipper, calls`f'` with the new "moved" zipper, moves the zipper again and so on, and so on ... until the zipper reaches the end of the list. Finally, the `cobind` returns a new zipper of type `Zipper[B]`, which can be transformed to the list and so the problem is solved. Now note the symmetry between `cobind[A](f:Zipper[A] => B):Zipper[B]` and `bind[A](f:A => List[B]):List[B]` That's why `List` is a `Monad` and `Zipper` is a `Comonad`. Does it make sense ?

Original source

Related problems