私はモナドが何であるかを知っています。コモナドとは何かについて、私は正しく理解できたと思います。(というか、これは単純に思えますが、これの何が役に立つのかを理解するのが難しい部分です...)
私の質問は次のとおりです。何かがモナドとコモナドになることができますか?
考えられる答えは 2 つあると思います。
- はい、これは一般的で広く有用です。
- いいえ、彼らは非常に異なる仕事をしているので、何かを両方にしたい理由はありません.
それで、それはどれですか?
私はモナドが何であるかを知っています。コモナドとは何かについて、私は正しく理解できたと思います。(というか、これは単純に思えますが、これの何が役に立つのかを理解するのが難しい部分です...)
私の質問は次のとおりです。何かがモナドとコモナドになることができますか?
考えられる答えは 2 つあると思います。
それで、それはどれですか?
はい。いくつかのコメントを答えに変える:
newtype Identity a = Identity {runIdenity :: a} deriving Functor
instance Monad Identity where
return = Identity
join = runIdentity
instance CoMonad Identity where
coreturn = runIdentity
cojoin = Identity
で示されるように、Reader と Writer は厳密な双対です。
class CoMonoid m where
comempty :: (m,a) -> a
comappend :: m -> (m,m)
--every haskell type is a CoMonoid
--that is because CCCs are boring!
instance Monoid a => Monad ((,) a) where
return x = (mempty,x)
join (a,(b,x)) = (a <> b, x)
instance CoMonoid a => CoMonad ((,) a) where
coreturn = comempty
cojoin = associate . first comappend
instance CoMonoid a => Monad ((->) a) where
return = flip (curry comempty)
join f = uncurry f . comappend
instance Monoid a => CoMonad ((->) a) where
coreturn f = f mempty
cojoin f a b = f (a <> b)
Monad
と の両方である興味深い構造がたくさんありますComonad
。
ファンクターは他のIdentity
何人かによってここで指摘されていますが、自明ではない例があります。
はとしてWriter
Monad
のReader
ような役割を果たしComonad
ます。
instance Monoid e => Monad ((,) e)
instance Comonad ((,) e)
はとしてReader
Monad
のWriter
ような役割を果たしComonad
ます。
instance Monad ((->) e)
instance Monoid e => Comonad ((->)e)
空でないリストもモナドと共通モナドの両方を形成し、実際には共自由共通モナドを含むより大きな構造の特殊なケースです。このIdentity
ケースは、この特殊なケースと見なすこともできます。
また、Kan 拡張に基づくさまざまな and に似た構造もありYoneda
、Codensity
モナドとコモナドを変換するために機能しますが、操作効率の点ではどちらか一方に有利です。
また、任意の共通モナドをモナド変換子に変換するアダプターもあります。残念ながら、Haskell では逆の変換はできません。
線形代数には双代数の概念があります。Monad
理想的には、aと a の両方を形成する何かがありComonad
、ケースバイケースで推論せずにこれらの操作を一緒に使用したい場合、return
それjoin
は Comonad 双極数であり、拡張によりextract
とduplicate
はMonad
代数です。Monad f
これらの条件が当てはまる場合、実際には、 と の両方のComonad f
制約を持ち、ケースバイケースの推論なしでそれぞれのコンビネータを混合するコードについて推論することができます。
Hammer の提案を拡張すると、 function を書くのは簡単に思えます[x] -> [[x]]
。例えば、
map (\ x -> [x])
うまくいくでしょう。したがって、リストは共通項を形成できるように見えます。あ、でも待って。それは を扱いますcojoin
が、どうcoreturn :: [x] -> x
ですか?おそらくこれが、空でないリストだけが共通項を形成する理由です。
これにより、 type の cobind 関数が得られます([x] -> x) -> [x] -> [x]
。興味深いことに、Hoogle はそのような関数を知りません。それでも、私たちはすでに持っていますconcatMap :: (x -> [x]) -> [x] -> [x]
。cobind 関数がすぐに使用されるとは思えませんが、存在することは想像できます。
私はまだcomonadとそれが何に役立つかについて頭を悩ませようとしています。これまでの回答は、私に考えさせる何かを与えてくれました...