Continuation モナド
理解するのにすごく苦労したのでメモ。
まず、定義はこんな感じ。
instance Monad (Cont r) where return a = Cont $ \k -> k a -- i.e. return a = \k -> k a (Cont c) >>= f = Cont $ \k -> c (\a -> runCont (f a) k) -- i.e. c >>= f = \k -> c (\a -> f a k)http://www.sampou.org/haskell/a-a-monads/html/contmonad.html
runCont
runContの中身が書いてないが、以下のような定義だと思われる。
第1引数にContモナドをとり、中身のcを取り出し、kに適用する。
runCont (Cont c) k = c k
bind
自分としては、>>=の中身は、以下のように2カ所にrunContを使った式の方がわかりやすいと思う。
なお、もとの定義での(Cont c)がccに対応する。
cc >>= f = Cont $ \k -> runCont cc (\a -> runCont (f a) k)
継続渡し→モナド
以上を踏まえて普通に書いた継続渡し版の階乗からモナド版の階乗を導いてみる。
fact 0 k = k 1 fact n k = fact (n - 1) (\a -> k $ n * a) main = fact 4 print
kを呼び出している部分を(\k -> k ...)に変形する。
fact 0 = \k -> k 1 fact n = \k -> fact (n - 1) (\a -> (\k -> k $ n * a) k) main = fact 4 print
(\k -> ...)を、Contモナド(Cont $ \k-> ...)にする。
これにあわせて、Contモナドに引数を適用しているところはrunContを介するようにする。
fact 0 = Cont $ \k -> k 1 fact n = Cont $ \k -> runCont (fact $ n - 1) (\a -> runCont (Cont $ \k -> k $ n * a) k) main = runCont (fact 4) print
(Cont $ \k -> k ...) を (return ...) に置き換える
fact 0 = return 1 fact n = Cont $ \k -> runCont (fact $ n - 1) (\a -> runCont (return $ n * a) k) main = runCont (fact 4) print
(fact $ n - 1) が cc、(return $ n * a) が (f a) に対応するので、>>=に置き換える。
なお、f a = x のとき、f = \a->x
fact 0 = return 1 fact n = (fact $ n - 1) >>= (\a -> return $ n * a) main = runCont (fact 4) print
さらにdo記法に変形して完了。
import Control.Monad.Cont fact 0 = return 1 fact n = do a <- fact $ n - 1 return $ n * a main = runCont (fact 4) print