次の Haskell の関数の例quux
と、継続モナド および の定義を考えてみましょうcallCC
。
instance Monad (Cont r) where
return x = cont ($ x)
s >>= f = cont $ \c -> runCont s $ \x -> runCont (f x) c
callCC :: ((a -> Cont r b) -> Cont r a) -> Cont r a
callCC f = cont $ \h -> runCont (f (\a -> cont $ \_ -> h a)) h
quux :: Cont r Int
quux = callCC $ \k -> do
let n = 5
k n
return 25
私がこの例を理解しているように。do ブロックは次のように考えることができます。
k n >>= \_ -> return 25 ==
cont $ \c -> runCont (k n) $ \x -> runCont ((\_ -> return 25) x) c
k
そして、 whichの定義から\a -> cont $ \_ -> h a
、上記では\x -> runCont ((\_ -> return 25) x) c
、アンダースコアで無視される引数に渡されていることがわかります。アンダースコア引数は決して使用されないため、最終的にreturn 25
は事実上「無視」されます。そのため、遅延評価から評価されることはありません。
callCC
したがって、この実装は基本的に遅延評価に強く依存していると言えます。callCC
厳密な (非遅延) 関数型言語でこれを行うにはどうすればよいでしょうか?