ArrowとApplicativeとは異なり、相互イールドによってArrowApplyとMonadsが同等になるのはなぜですか?


8

これが私が参照するSOの投稿ですまた、資料を分離しないために、その質問ではOPと同じスニペットを使用します

インスタンスがモナドを生成すること、およびその逆が広く知られていArrowApplyます。

newtype ArrowMonad a b = ArrowMonad (a () b)

instance Arrow a => Functor (ArrowMonad a) where
    fmap f (ArrowMonad m) = ArrowMonad $ m >>> arr f

instance Arrow a => Applicative (ArrowMonad a) where
   pure x = ArrowMonad (arr (const x))
   ArrowMonad f <*> ArrowMonad x = ArrowMonad (f &&& x >>> arr (uncurry id))

instance ArrowApply a => Monad (ArrowMonad a) where
    ArrowMonad m >>= f = ArrowMonad $
        m >>> arr (\x -> let ArrowMonad h = f x in (h, ())) >>> app

newtype Kleisli m a b = Kleisli { runKleisli :: a -> m b }

instance Monad m => Category (Kleisli m) where
    id = Kleisli return
    (Kleisli f) . (Kleisli g) = Kleisli (\b -> g b >>= f)

instance Monad m => Arrow (Kleisli m) where
    arr f = Kleisli (return . f)
    first (Kleisli f) = Kleisli (\ ~(b,d) -> f b >>= \c -> return (c,d))
    second (Kleisli f) = Kleisli (\ ~(d,b) -> f b >>= \c -> return (d,c))

そして、上記の記事に出くわすまで、このスニペットはArrowApplyMonadクラスの同等性のもっともらしい証明であると感じました。しかし、ArrowとApplicativeは実際には同等ではないことを知っているので、次のスニペットは、Monadとの同等性の完全な証明に興味を持ちましたArrowApply

newtype Arrplicative arr o a = Arrplicative{ runArrplicative :: arr o a }

instance (Arrow arr) => Functor (Arrplicative arr o) where
    fmap f = Arrplicative . (arr f .) . runArrplicative

instance (Arrow arr) => Applicative (Arrplicative arr o) where
    pure = Arrplicative . arr . const

    Arrplicative af <*> Arrplicative ax = Arrplicative $
        arr (uncurry ($)) . (af &&& ax)

newtype Applicarrow f a b = Applicarrow{ runApplicarrow :: f (a -> b) }

instance (Applicative f) => Category (Applicarrow f) where
    id = Applicarrow $ pure id
    Applicarrow g . Applicarrow f = Applicarrow $ (.) <$> g <*> f

instance (Applicative f) => Arrow (Applicarrow f) where
    arr = Applicarrow . pure
    first (Applicarrow f) = Applicarrow $ first <$> f

>したがって、アプリケーションを介して往復すると、一部の機能が失われます。 例が提供されている場合、それは明らかです、まだ私はモナドはすべてArrowApplyが最初に我々はいくつかの入力(に依存矢印を持っていたので、備えて保存して、「ラウンドトリップ」する方法を把握することができないa b c)が、最後に、我々は、で終わります入力タイプがユニットタイプであるラッパーに強制された矢印(ArrowMonad (a () b))。

ここで私がひどく間違ったことをしているのは明らかですが、正確には何を理解できません。

完全な証拠は何であるArrowApplyMonad等価ですか?

の非等価性の例ArrowApplicative説明は何ですか?ある人は別の人を一般化しますか?

アロー計算とカテゴリー理論におけるその全体的な状況の解釈は何ですか?

完全な説明と、証拠となるものを自分で作成するのに役立つヒントの両方をいただければ幸いです。

回答:


3

最初はいくつかの入力に依存する矢印があったので(a b c)、結局、入力タイプとしてユニットタイプを持つラッパーに矢印が強制されます(ArrowMonad (a () b)

これが混乱の中心点だと思いますが、実は混乱しています。私はあなたがこれを取得しませんデカルトモノイド圏、中にほとんどの射として矢印と考えたいが、すでにArrowクラスが実際より制限よりのおかげであるarr-からあなたにファンクタを与えるHaskカテゴリに。しかし、多少意外なことに、これには方向のマッピングも必要になります。どの矢印も、単純なドメインの矢印だけを生成する関数に置き換えることができます。具体的には、

arrAsFunction :: Arrow k => k x y -> (x -> k () y)
arrAsFunction φ x = φ <<< arr (const x)

それだけでは、あまりにも大きな影響はありません。おそらく、ここで一部の情報を破棄しただけでしょうか。–しかし、ArrowApplyこれは実際には同型です。次の方法で元の矢を取り戻すことができます

retrieveArrowFromFunction ::  k x y .
          ArrowApply k => (x -> k () y) -> k x y
retrieveArrowFromFunction f = arr f' >>> app
 where f' :: x -> (k () y, ())
       f' x = (f x, ())

...これはまさにMonad (ArrowMonad a)インスタンスで使用されているものです。

つまり、arrカテゴリにHaskell関数を埋め込むことができることを要求することにより、カテゴリは基本的に、結果の周りにいくつかのラッパー持つ関数に集約され、IOWはKleisli矢印のようなものになります。

他のカテゴリ理論の階層を調べて、これがデカルトのモノイドカテゴリの基本的な機能ではなく、実際にHaskk関数のアーティファクトであることを確認してください。例えば制約-カテゴリ内の私は、密接に標準クラスを反映してきましたPreArrowデカルトmonoidalカテゴリのクラスとしてではなく、故意に保たれarr、それから出て、それに特定しなかったHaskカテゴリの能力ダウンそれdumbsがあまりにも多くあるため、そして、それはほぼ相当することになりHask -Kleisli。


あなたの答えをありがとう-それは今よりずっと意味があります!ArrowApply / Monadの同等性について話すとき、同型のその部分がしばしば考慮から外される理由はありますか?それとも、直感的なリードを厳密な証拠と間違えただけですか?
Zhiltsoff Igor

さて、「モナドは型同型満足矢印と同等であるABA →(1件の↝ B気づか/細心/無差別論文のアブストラクトに権利があります...)」。なぜこのPOVが通常それほど議論されないのか、私にはわかりません。
1
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.