[关闭]
@MiloXia 2016-01-13T14:48:10.000000Z 字数 2493 阅读 1744

Comonad

scala 函数式编程


Comonad

逆Monad, 定义:

  1. //A comonad is the same thing as a monad, only backwards
  2. trait Comonad[W[_]] extends Functor[W] {
  3. def counit[A](w: W[A]): A //又名extract
  4. def duplicate[A](wa: W[A]): W[W[A]]
  5. }

extend/coKleisli

是flatMap的逆向
(W[A] -> B) -> W[A] -> W[B]

  1. //参数与flatMap是反的,接W[A] -> A的函数,comonads的组合又叫coKleisli,逆Kleisli
  2. def extend[B](f: Coreader[R,A] => B): Coreader[R,B] =
  3. duplicate map f

Comonad laws

例子

Id

等价于Id Monad

  1. case class Id[A](a: A) {
  2. def map[B](f: A => B): Id[B] = Id(f(a))
  3. def counit: A = a
  4. def duplicate: Id[Id[A]] = Id(this)
  5. }

Reader

monad

语义:当R准备好时(最后调用run传入),从R中读取出A
composition的语义:只能看到部分操作的结构A,用于后续的(map/flatMap)操作

  1. case class Reader[R,A](run: R => A)
  2. def ask[R]: Reader[R,R] = Reader(r => r) //unit
  3. def join[R,A](r: Reader[R,Reader[R,A]]) =
  4. Reader((c:R) => r.run(c).run(c))
comonad

语义:

we don’t have to pretend to have an R value. It’s just right there and we can look at it.

不需要提供(也就是run方法)R一开始就提供好了,直接取出值
composition的语义:获得全部的上下文W[A],用于后续的(extend)操作

The name extend refers to the fact that it takes a “local” computation that operates on some structure and “extends” that to a “global” computation that operates on all substructures of the larger structure.

  1. case class Coreader[R,A](extract: A, ask: R) {
  2. def map[B](f: A => B): Coreader[R,B] = Coreader(f(extract), ask)
  3. def duplicate: Coreader[R, Coreader[R, A]] =
  4. Coreader(this, ask)
  5. def extend[B](f: Coreader[R,A] => B): Coreader[R,B] =
  6. duplicate map f
  7. }
  8. def coreaderComonad[R]: Comonad[Coreader[R,?]] =
  9. new Comonad[Coreader[R,?]] {
  10. def map[A,B](c: Coreader[R,A])(f: A => B) = c map f
  11. def counit[A](c: Coreader[R,A]) = c.extract
  12. def duplicate(c: Coreader[R,A]) = c.duplicate
  13. }

writer

monad

语义:往W中append A (W已经准备好,不需要run方法)
composition的语义:只能看到部分操作的结构W,用于后续的(map/flatMap)操作

  1. case class Writer[W,A](value: A, log: W)
  2. def tell[W,A](w: W): Writer[W,Unit] = Writer((), w)
  3. def join[W:Monoid,A](w: Writer[W,Writer[W,A]]) =
  4. Writer(w.value.value, Monoid[W].append(w.log, w.value.log))
  5. def unit[W:Monoid,A](a: A) = Writer(a, Monoid[W].zero)
comonad

语义:

But instead of keeping the log always available to be appended to, it uses the same trick as the reader monad by building up an operation that gets executed once a log becomes available

当W准备好时(最后调用tell传入),从W中写入(看duplicate方法)
composition的语义:获得全部的上下文W[A],用于后续的(extend)操作

  1. case class Cowriter[W:Monoid,A](tell: W => A) {
  2. def map[B](f: A => B): Cowriter[W,B] = Cowriter(tell andThen f)
  3. def extract = tell(Monoid[W].zero)
  4. def duplicate: Cowriter[W, Cowriter[W, A]] =
  5. Cowriter(w1 => Cowriter(w2 => tell(Monoid[W].append(w1, w2))))
  6. def extend[B](f: Cowriter[W,A] => B): Cowriter[W,B] =
  7. duplicate map f
  8. }

总结1

语义上Comonad与Monad是逆反的

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注