17

Monad.Reader#13のBrent Yorgey による「The Typeclassopedia」を読んだところ、図 1 に示すように、「Functor 階層」が「Category 階層」と相互依存していることがわかりました。

図1

著者によるとArrowApply == Monad、特に前のものは、次の場合に使用できる単なる型クラスのインスタンスであるとのことです。

「中間結果から矢印を計算し、この計算された矢印を使用して計算を続行できるようにしたいと考えています。これが、ArrowApply によって与えられた力です。」

しかし、どうすればこれらのものをまとめることができるでしょうか? つまり、Monad と Arrow の両方にいくつかのフロー制御関数 ( ifand elsevs. ArrowChoice、またはforMvs.など) があり、Monad ( 、または)ArrowLoopに「欠けている」ように見える機能もあります。これらはすべて、副作用の計算フローを構築するために Monad または Arrow システムのどちらを使用するかを選択する必要があるように思われ、別のシステムではいくつかの機能が失われます。(***)(|||)first

4

1 に答える 1

12

答えは次のとおりです(これはすべてControl.Arrow docsからのものです)

newtype ArrowApply a => ArrowMonad a b = ArrowMonad (a () b)
instance Monad ArrowApply a => Monad (ArrowMonad a)

newtype は、矢印のインスタンスArrowMonadを定義する手段です。使用できたはずですMonadArrowApply

instance Monad ArrowApply a => Monad (a ())

しかし、これは Haskell の制限された型クラスの推論で問題を引き起こしたでしょう (それはUndecideableInstances拡張機能で動作するだろうと私は推測しています)。

ソースが示すように、矢印のMonadインスタンスは、モナド操作を同等の矢印操作に変換するものと考えることができます。ArrowApply

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

そのため、すべての操作を実装できるため、これは非常に強力であることArrowApplyがわかっています。驚くべきことに、その逆も成り立ちます。@hammarが指摘したように、これはnewtypeによって与えられます。観察:MonadMonadKleisli

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))

instance Monad m => ArrowApply (Kleisli m) where
        app = Kleisli (\(Kleisli f, x) -> f x)

instance Monad m => ArrowChoice (Kleisli m) where
    left f = f +++ arr id
    right f = arr id +++ f
    f +++ g = (f >>> arr Left) ||| (g >>> arr Right)
    Kleisli f ||| Kleisli g = Kleisli (either f g)

前のものは、モナド操作を使用した通常のすべてのアロー操作の実装を提供します。および を(***)使用するデフォルトの実装があるため、言及されていません。firstsecond

f *** g = first f >>> second g

これで、 Monad 操作を使用して矢印 ( ArrowArrowChoice、 ) 操作を実装する方法がわかりました。ArrowApply


Monad両方を持っている理由とArrow、それらが同等であることが判明したかどうかについてのあなたの質問に答えるには:

弱いアローは、アプリカティブ ファンクタが有用であるのと同様に、モナドのフル パワーを必要としない場合に有用です。そして、ArrowApplyMonadは同等ですが、ArrowまたはArrowChoiceなしappは、Monad階層で表現できないものです。逆に、Applicativeは矢印階層で表現できません。これはap、モナド階層では「最初」、アロー階層では「最後」になるためです。

モナドとアローの世界の主な意味上の違いは、アローは変換をキャプチャする (arr b cつまり、 acからを生成するb) のに対し、モナドは操作をキャプチャする (monad aを生成するa) ことです。この違いは、KleisliArrowMonadnewtypesによく反映されています。

newtype Kleisli m a b = Kleisli { runKleisli :: a -> m b }
newtype ArrowApply a => ArrowMonad a b = ArrowMonad (a () b)

Kleisliソース タイプを追加する必要がaあり、ArrowMonadに設定し()ます。


これがあなたを満足させることを願っています!

于 2011-12-03T10:54:34.127 に答える