21

What is Comonad, if it's possible describe in Scala syntax. I found scalaz library implementation, but it's not clear where it can be useful.

soc
  • 27,983
  • 20
  • 111
  • 215
Stas
  • 751
  • 1
  • 11
  • 22
  • 2
    See also: [What is the Comonad typeclass in Haskell](http://stackoverflow.com/questions/8428554/what-is-the-comonad-typeclass-in-haskell). Scalaz generally tries to make things as Haskell-ish as possible, so those blog posts may help. – Dan Burton Jun 19 '12 at 21:48
  • Also see also: recent reddit post at /r/haskell [A Notation for Comonads](http://www.reddit.com/r/haskell/comments/v6ik6/a_notation_for_comonads_orchard_mycroft_pdf/) – Dan Burton Jun 19 '12 at 21:50

3 Answers3

12

Well, monads allow you to add values to them, change them based on a computation from a non-monad to a monad. Comonads allow you to extract values from them, and change them based on a computation from a comonad to a non-comonad.

The natural intuition is that they'll usually appear where you have a CM[A] and want to extract A.

See this very interesting post that touches on comonads a bit casually, but, to me at least, making them very clear.

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
  • "The natural intuition is that they'll usually appear where you have a CM[A] and want to extract A." That's `Copointed`/`Copure`. Add to it `extract` (`W[A] => (W[A] => B) => W[B]`) or `cojoin` (`W[A] => W[W[A]]`), and you get `Comonad`. – missingfaktor Jun 20 '12 at 05:37
  • @missingfaktor I am not defining them -- I assume Stas has seen the definition already. I am saying comonads will usually be found in situations like this. – Daniel C. Sobral Jun 20 '12 at 15:16
7

What follows is a literal translation of code from this blog post.

case class U[X](left: Stream[X], center: X, right: Stream[X]) {
  def shiftRight = this match {
    case U(a, b, c #:: cs) => U(b #:: a, c, cs)
  }

  def shiftLeft = this match {
    case U(a #:: as, b, c) => U(as, a, b #:: c)
  }
}

// Not necessary, as Comonad also has fmap.
/*
implicit object uFunctor extends Functor[U] {
  def fmap[A, B](x: U[A], f: A => B): U[B] = U(x.left.map(f), f(x.center), x.right.map(f))
}
*/

implicit object uComonad extends Comonad[U] {
  def copure[A](u: U[A]): A = u.center
  def cojoin[A](a: U[A]): U[U[A]] = U(Stream.iterate(a)(_.shiftLeft).tail, a, Stream.iterate(a)(_.shiftRight).tail)
  def fmap[A, B](x: U[A], f: A => B): U[B] = U(x.left.map(f), x.center |> f, x.right.map(f))
}

def rule(u: U[Boolean]) = u match {
  case U(a #:: _, b, c #:: _) => !(a && b && !c || (a == b))
}

def shift[A](i: Int, u: U[A]) = {
  Stream.iterate(u)(x => if (i < 0) x.shiftLeft else x.shiftRight).apply(i.abs)
}

def half[A](u: U[A]) = u match {
  case U(_, b, c) => Stream(b) ++ c
}

def toList[A](i: Int, j: Int, u: U[A]) = half(shift(i, u)).take(j - i)

val u = U(Stream continually false, true, Stream continually false)

val s = Stream.iterate(u)(_ =>> rule)

val s0 = s.map(r => toList(-20, 20, r).map(x => if(x) '#' else ' '))

val s1 = s.map(r => toList(-20, 20, r).map(x => if(x) '#' else ' ').mkString("|")).take(20).force.mkString("\n")

println(s1)

Output:

 | | | | | | | | | | | | | | | | | | | |#| | | | | | | | | | | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#|#| | | | | | | | | | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#| |#| | | | | | | | | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#|#|#|#| | | | | | | | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#| | | |#| | | | | | | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#|#| | |#|#| | | | | | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#| |#| |#| |#| | | | | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#|#|#|#|#|#|#|#| | | | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#| | | | | | | |#| | | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#|#| | | | | | |#|#| | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#| |#| | | | | |#| |#| | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#|#|#|#| | | | |#|#|#|#| | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#| | | |#| | | |#| | | |#| | | | | | |
 | | | | | | | | | | | | | | | | | | | |#|#| | |#|#| | |#|#| | |#|#| | | | | |
 | | | | | | | | | | | | | | | | | | | |#| |#| |#| |#| |#| |#| |#| |#| | | | |
 | | | | | | | | | | | | | | | | | | | |#|#|#|#|#|#|#|#|#|#|#|#|#|#|#|#| | | |
 | | | | | | | | | | | | | | | | | | | |#| | | | | | | | | | | | | | | |#| | |
 | | | | | | | | | | | | | | | | | | | |#|#| | | | | | | | | | | | | | |#|#| |
 | | | | | | | | | | | | | | | | | | | |#| |#| | | | | | | | | | | | | |#| |#|
 | | | | | | | | | | | | | | | | | | | |#|#|#|#| | | | | | | | | | | | |#|#|#|#
missingfaktor
  • 90,905
  • 62
  • 285
  • 365
  • Import for `Comonad` is missing. `=>>` and `|>` are not defined too. – EnverOsmanov Feb 27 '17 at 09:57
  • 1
    @EnverOsmanov, this post is from a time when I did not realise the importance of including imports in code snippets. :-) Anyway, Scalaz has changed hugely since, and the packages have seen multiple reorganisation rounds. I would appreciate it if you could update this post as per new Scalaz (or Cats, if that's your poison). – missingfaktor Feb 28 '17 at 10:41
1

The scalaz library provides a ComonadStore which extends the property of Comonad. It is defined like this:

trait ComonadStore[F[_], S] extends Comonad[F] { self =>

  def pos[A](w: F[A]): S
  def peek[A](s: S, w: F[A]): A

  def peeks[A](s: S => S, w: F[A]): A =
    peek(s(pos(w)), w)

  def seek[A](s: S, w: F[A]): F[A] =
    peek(s, cojoin(w))

  def seeks[A](s: S => S, w: F[A]): F[A] =
    peeks(s, cojoin(w))

  def experiment[G[_], A](s: S => G[S], w: F[A])(implicit FG: Functor[G]): G[A] =
    FG.map(s(pos(w)))(peek(_, w))

}

And a Store( which is analogous to (S => A, S)) has an instance of Comonad. You can look at this question that explains what it is more specifically.

You also have the Coreader and Cowriter Comonads that are the dual of the Reader and Writer Monads, here is an excellent blog post that talks about it in Scala.

Valy Dia
  • 2,781
  • 2
  • 12
  • 32