2012-06-19 81 views
19

什麼是Comonad,如果可以用Scala語法描述的話。 我發現scalaz庫的實現,但它不清楚它可以用在哪裏。Scala中的Comonad示例

+1

另請參見:[什麼是Haskell中的Comonad類型類型](http://stackoverflow.com/questions/8428554/what-is-the-comonad-typeclass-in-haskell)。斯卡拉斯通常儘可能將Haskell-ish做成事情,所以這些博客文章可能會有所幫助。 –

+0

另請參閱:/ r/haskell中的最近reddit文章[Comonads的表示法](http://www.reddit.com/r/haskell/comments/v6ik6/a_notation_for_comonads_orchard_mycroft_pdf/) –

回答

12

好,單子讓你值添加到他們,改變他們根據從非單子到單子計算。 Comonads允許您從中提取值,並根據從comonad到非comonad的計算來更改它們。

自然的直覺是,他們通常會在出現在你有一個CM [A]和要提取A.

this非常有趣的帖子上comonads倒是有點漫不經心,但對我來說至少,使他們非常清楚。

+0

「自然的直覺是,他們通常會出現在你有CM [A]並且想要提取A的地方。」這是'Copointed' /'Copure'。添加到它'extract [(W [A] =>(W [A] => B)=> W [B]')或'cojoin'('W [A] => W [W [A]] '),你會得到'Comonad'。 – missingfaktor

+0

@missingfaktor我沒有定義它們 - 我認爲Stas已經看到了定義。我說的是通常會在這種情況下發現連接器。 –

7

接下來是從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) 

輸出:

| | | | | | | | | | | | | | | | | | | |#| | | | | | | | | | | | | | | | | | | 
| | | | | | | | | | | | | | | | | | | |#|#| | | | | | | | | | | | | | | | | | 
| | | | | | | | | | | | | | | | | | | |#| |#| | | | | | | | | | | | | | | | | 
| | | | | | | | | | | | | | | | | | | |#|#|#|#| | | | | | | | | | | | | | | | 
| | | | | | | | | | | | | | | | | | | |#| | | |#| | | | | | | | | | | | | | | 
| | | | | | | | | | | | | | | | | | | |#|#| | |#|#| | | | | | | | | | | | | | 
| | | | | | | | | | | | | | | | | | | |#| |#| |#| |#| | | | | | | | | | | | | 
| | | | | | | | | | | | | | | | | | | |#|#|#|#|#|#|#|#| | | | | | | | | | | | 
| | | | | | | | | | | | | | | | | | | |#| | | | | | | |#| | | | | | | | | | | 
| | | | | | | | | | | | | | | | | | | |#|#| | | | | | |#|#| | | | | | | | | | 
| | | | | | | | | | | | | | | | | | | |#| |#| | | | | |#| |#| | | | | | | | | 
| | | | | | | | | | | | | | | | | | | |#|#|#|#| | | | |#|#|#|#| | | | | | | | 
| | | | | | | | | | | | | | | | | | | |#| | | |#| | | |#| | | |#| | | | | | | 
| | | | | | | | | | | | | | | | | | | |#|#| | |#|#| | |#|#| | |#|#| | | | | | 
| | | | | | | | | | | | | | | | | | | |#| |#| |#| |#| |#| |#| |#| |#| | | | | 
| | | | | | | | | | | | | | | | | | | |#|#|#|#|#|#|#|#|#|#|#|#|#|#|#|#| | | | 
| | | | | | | | | | | | | | | | | | | |#| | | | | | | | | | | | | | | |#| | | 
| | | | | | | | | | | | | | | | | | | |#|#| | | | | | | | | | | | | | |#|#| | 
| | | | | | | | | | | | | | | | | | | |#| |#| | | | | | | | | | | | | |#| |#| 
| | | | | | | | | | | | | | | | | | | |#|#|#|#| | | | | | | | | | | | |#|#|#|# 
+0

缺少「Comonad」的導入。 '= >>'和'|>'也沒有定義。 – EnverOsmanov

+0

@EnverOsmanov,這篇文章是從我沒有意識到在代碼片段中包含import的重要性的時候開始的。 :-)無論如何,斯卡拉茲已經發生了巨大的變化,而且這些軟件包已經進行了多輪重組。如果你能按照新斯卡拉斯(或者貓,如果那是你的毒藥)更新這篇文章,我將不勝感激。 – missingfaktor