9

特にモナドでどのように機能するかについて、アロー表記を理解しようとしています。モナドを使用すると、次のように定義できます。

f = (*2)
g = Just 5 >>= (return . f)

そしてg_Just 10

矢印表記を使用して上記を行うにはどうすればよいですか?

4

2 に答える 2

11

モナド思考をアロー思考に変える

Arrow に変換するための最初のステップはm b、それ自体で考えるのではなく、 について考えるようにすることa -> m bです。

モナドで、あなたは書くでしょう

use x = do
   .....
   ....
doThis = do
   ....
   ...

thing = doThis >>= use

一方、矢印には常に入力があるため、そうする必要があります

doThis' _ = do
   .....
   ....

そして(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m cfrom Control.Monaddo haveを使用します

thing' = doThis' >=> use

>=>の非対称性を取り除き、>>=モナドのクライスリの矢と呼ぶものです。

()入力または「私の最初のものが本当に関数ではない場合はどうなりますか?」の使用

それは問題ありません。モナドが何も生成しない場合 (putStrLn が生成しないように) の副問題ですreturn ()

あなたの事がデータを必要としない場合は()、引数として取る関数にしてください。

doThis () = する .... ....

そうすれば、すべてに署名がa -> m bあり、それらを で連鎖させることができます>=>

矢印には入力と出力がありますが、機能はありません

矢印には署名があります

Arrow a => a b c

これはおそらく中置記号よりも明確ではありません

Arrow (~>) => b ~> c

しかし、あなたはそれを に似ていると考えるべきですb -> m c

主な違いは、関数の引数としてb -> m cyourbを使用すると、それで好きなことを行うことができif b == "war" then launchMissiles else return ()ますが、矢印ではできません (ArrowApply でない限り、ArrowApply が Monad 機能を提供する理由については、この質問を参照してください)。 -一般に、アローはその機能を実行するだけで、データに基づいて操作を切り替えることはできません。これは、Applicative の場合と少し似ています。

モナドをアローに変換する

問題は、インスタンス宣言でそれを部分的に適用して中央からビットb -> m cを取得できないことです。そのため、Kleisli 矢印と呼ばれる場合、すべてのラップとアンラップの後に= - が得られるように定義されますが、これはと同等です。(実際、は forwards composition ではなく、カテゴリに対して定義されていますが、同等だと言いました!)-> mb -> m cControl.Monad(>>>)f >>> g\x -> f x >>= g(>>>) = (>=>)(.)>>>

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) -- composition of Kleisli arrows

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

あなたの例、ついに

Kleisli(すべてのandを無視するようにしてくださいrunKleisli。それらは単にモナド値をラップおよびアンラップしているだけです。独自の矢印を定義する場合、それらは必要ありません。)

それが にとって何を意味するかをアンラップするMaybeと、作曲と同等の結果が得られます

f :: a -> Maybe b
g :: b -> Maybe c
f >>> g :: a -> Maybe c  
f >>> g = \a -> case f a of       -- not compilable code!
                Nothing -> Nothing
                Just b -> g b

(純粋な)関数を適用する矢印の方法はarr :: Arrow (~>) => (b -> c) -> b ~> c

実際の動作を確認できるように、次のように修正(~->)します。Kleisli Maybe

{-# LANGUAGE TypeOperators #-}
import Control.Arrow
type (~->) = Kleisli Maybe

g :: Integer ~-> Integer
g = Kleisli Just >>> arr (*2)

与える

ghci> runKleisli g 10
Just 20

記法と同様doですが、入力と出力があります。(GHC)

doGHC は記法に相当する記法を実装してprocいます。

output <- arrow -< input

あなたは慣れてoutput <- monadいますが、今はarrow -< input表記があります。モナドと同じよう<-に、最後の行では行いませんproc。記法でも行いません。

表記を説明するために、tail と read from safeの Maybe バージョンを使用してみましょう(そして、 をアドバタイズしsafeます)。

{-# LANGUAGE Arrows #-}
import Control.Arrow
import Safe

this = proc inputList -> do
    digits <- Kleisli tailMay -< inputList
    number <- Kleisli readMay -<< digits
    arr (*10) -<< number

-<<のバリアントを使用したことに注意してください。これにより、 の左側にあるものを の右側にあるスコープに-<持ち込むことで、出力を入力として使用できます。<--<

明らかthisに と同等Kleisli tailMay >>> Kleisli readMay >>> arr (*10)ですが、アイデアを提供するためだけに (!) 使用しています。

ghci> runKleisli this "H1234"  -- works
Just 1234
ghci> runKleisli this "HH1234"  -- readMay fails
Nothing
ghci> runKleisli this ""     -- tailMay fails
Nothing
ghci> runKleisli this "10"     -- works
Just 0

すべてのこと()

私が言ったように、()入力がない場合は使用し、Monad で行うように、何も出力する必要がない場合はそれを返します。

表記例にも次のように表示()されます。proc

thing = proc x -> do
     this <- thing1 -< ()
     () <- thing2 -< x
     returnA -< this
于 2014-02-16T16:40:59.683 に答える