【问题标题】:Comonad example in ScalaScala 中的 Comonad 示例
【发布时间】:2012-06-21 23:40:52
【问题描述】:

什么是 Comonad,如果可以用 Scala 语法来描述的话。 我找到了scalaz 库实现,但不清楚它在哪里有用。

【问题讨论】:

标签: scala monads scalaz comonad


【解决方案1】:

嗯,monad 允许您向它们添加值,根据计算将它们从非 monad 更改为 monad。 Comonad 允许您从中提取值,并根据计算将它们从 Comonad 更改为 non-comonad。

自然的直觉是,它们通常会出现在您有 CM[A] 并想要提取 A 的地方。

请参阅this 非常有趣的帖子,它有点随意地触及了共胞,但至少对我来说,让它们非常清楚。

【讨论】:

  • “自然的直觉是,它们通常会出现在您有 CM[A] 并想要提取 A 的地方。”那是Copointed/Copure。添加到它extract (W[A] => (W[A] => B) => W[B]) 或cojoin (W[A] => W[W[A]]),你会得到Comonad
  • @missingfaktor 我没有定义它们——我假设 Stas 已经看到了定义。我是说comonads 通常会出现在这种情况下。
【解决方案2】:

以下是来自this 博客文章的代码的字面翻译。

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)

输出:

 | | | | | | | | | | | | | | | | | | | |#| | | | | | | | | | | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#|#| | | | | | | | | | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#| |#| | | | | | | | | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#|#|#|#| | | | | | | | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#| | | |#| | | | | | | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#|#| | |#|#| | | | | | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#| |#| |#| |#| | | | | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#|#|#|#|#|#|#|#| | | | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#| | | | | | | |#| | | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#|#| | | | | | |#|#| | | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#| |#| | | | | |#| |#| | | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#|#|#|#| | | | |#|#|#|#| | | | | | | |
 | | | | | | | | | | | | | | | | | | | |#| | | |#| | | |#| | | |#| | | | | | |
 | | | | | | | | | | | | | | | | | | | |#|#| | |#|#| | |#|#| | |#|#| | | | | |
 | | | | | | | | | | | | | | | | | | | |#| |#| |#| |#| |#| |#| |#| |#| | | | |
 | | | | | | | | | | | | | | | | | | | |#|#|#|#|#|#|#|#|#|#|#|#|#|#|#|#| | | |
 | | | | | | | | | | | | | | | | | | | |#| | | | | | | | | | | | | | | |#| | |
 | | | | | | | | | | | | | | | | | | | |#|#| | | | | | | | | | | | | | |#|#| |
 | | | | | | | | | | | | | | | | | | | |#| |#| | | | | | | | | | | | | |#| |#|
 | | | | | | | | | | | | | | | | | | | |#|#|#|#| | | | | | | | | | | | |#|#|#|#

【讨论】:

  • Comonad 的导入丢失。 =&gt;&gt;|&gt; 也没有定义。
  • @EnverOsmanov,这篇文章是从我没有意识到在代码 sn-ps 中包含导入的重要性的时候。 :-) 无论如何,Scalaz 从那以后发生了巨大的变化,并且包已经经历了多轮重组。如果您能按照新的 Scalaz(或 Cats,如果那是您的毒药)更新这篇文章,我将不胜感激。
【解决方案3】:

scalaz library 提供了一个ComonadStore,它扩展了Comonad 的属性。它是这样定义的:

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))

}

Store(类似于(S =&gt; A, S))有一个Comonad 的实例。你可以看看这个question,它更具体地解释了它的含义。

您还拥有CoreaderCowriter Comonads,它们是ReaderWriter Monads 的对偶,这里有一篇很棒的blog 帖子,在Scala 中讨论了它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-16
    • 2020-03-26
    • 2013-07-20
    • 1970-01-01
    相关资源
    最近更新 更多