5

モナドを計算コンテキストとして記述することができ、モナドの実装はそのコンテキストの意味を正確に保持します。たとえば、オプション - コンテキストの意味は、値存在する可能性があるということです。Option データ型が与えられた場合、意味のある唯一の実装はpure = some, flatMap f = {none => none; some x => f x } 次のとおりです。私のモナドの理解として、型シグネチャに従うことにより、どのモナドにも合理的な実装は 1 つしかありません。言い換えれば、値/計算に意味のあるコンテキストを追加したい場合、特定のモナドに対してそれを行う方法は 1 つしかありません。
一方、comonad に関しては、特定の型の comonad を実装する方法がたくさんあり、すべての実装に特定の意味を与えることさえあるように、突然完全に奇妙に感じ始めます。
NEL を考えてみましょうcopure = head。 は、型を完全に満たすcojoinを介して実装されます。によって、またはそのままtails実装すると、コモンド法を満たさなくなります。ただし、循環実装は有効です。cojoinpermutationsfa 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 に立っています, そしてそこからどこかに行きたい
ので、それを行う方法は他にもたくさんあります.そうですか?別の意味のある抽象化を行うたびに、別の方法でコマンドを実装できますか?または末尾のみ実装は、コモナドが持ち込むことを想定している抽象化のため、合理的です。

4

2 に答える 2

1

これは同じ反例で、ピッグワーカーのコメントから、モナドに複数の可能なインスタンスがあることを示していますが、より多くの作業が行われています (ただし、型チェックされていないため、エラーを許してください)。

data WithBool a = WB Bool a deriving Functor

instance Monad WithBool where
     return = WB z
     (WithBool b a) >>= f =
           case f a of (WithBool b2 r) -> WithBool (b `op` b2) r

-- This holds if op = (&&) and z = True
-- This also holds if op = (||) and z = False
-- It should also work if op = const or `flip const` and z = True _or_ False

したがって、Bakuriu が言うように、「デフォルト」の実装の選択はいくぶん恣意的であり、人々が期待するものによって条件付けられます。

于 2016-03-04T18:24:54.140 に答える