モナドを計算コンテキストとして記述することができ、モナドの実装はそのコンテキストの意味を正確に保持します。たとえば、オプション - コンテキストの意味は、値が存在する可能性があるということです。Option データ型が与えられた場合、意味のある唯一の実装はpure = some, flatMap f = {none => none; some x => f x }
次のとおりです。私のモナドの理解として、型シグネチャに従うことにより、どのモナドにも合理的な実装は 1 つしかありません。言い換えれば、値/計算に意味のあるコンテキストを追加したい場合、特定のモナドに対してそれを行う方法は 1 つしかありません。
一方、comonad に関しては、特定の型の comonad を実装する方法がたくさんあり、すべての実装に特定の意味を与えることさえあるように、突然完全に奇妙に感じ始めます。
NEL を考えてみましょうcopure = head
。 は、型を完全に満たすcojoin
を介して実装されます。によって、またはそのままtails
実装すると、コモンド法を満たさなくなります。ただし、循環実装は有効です。cojoin
permutations
fa map (_ => fa) map f
override def cobind[A, B](fa: NonEmptyList[A])(f: (NonEmptyList[A]) => B): NonEmptyList[B] = {
val n: NonEmptyList[NonEmptyList[A]] = fa.map(_ => fa).zipWithIndex.map { case (li , i ) =>
val(h: List[A], t: List[A]) = li.list.splitAt(i)
val ll: List[A] = t ++ h
NonEmptyList.nel(ll.head, ll.tail)
}
n map f
}
私が見ているように、法律が私たちを制限しているにもかかわらず、コマンドがそのように曖昧である理由は、Monad で何らかのコンテキストで自分自身を制限する場合 (新しい情報を「作成」することはできません)、Comonad では、そのコンテキストをさらに拡張する (リストからリストのリストを作成するかなりの方法があります), これにより、それを行う可能性がさらに広がります. 私の頭の比喩は: モナドの場合, 私たちは道に立っていて、いくつかに到達したいです.目的地 A = したがって、選択する意味のある最短の方法しかありません. コマンドでは、私たちは A に立っています, そしてそこからどこかに行きたい
ので、それを行う方法は他にもたくさんあります.そうですか?別の意味のある抽象化を行うたびに、別の方法でコマンドを実装できますか?または末尾のみ実装は、コモナドが持ち込むことを想定している抽象化のため、合理的です。