モナド列から抜け出すことは可能ですか?
たとえば、シーケンスの途中で計算された条件に基づいて、シーケンスから早く抜け出したい場合。たとえば、「do」表記で値をバインドし、その値に基づいてシーケンスを終了または停止したいとします。「パス」機能のようなものはありますか?
ありがとう。
モナド列から抜け出すことは可能ですか?
たとえば、シーケンスの途中で計算された条件に基づいて、シーケンスから早く抜け出したい場合。たとえば、「do」表記で値をバインドし、その値に基づいてシーケンスを終了または停止したいとします。「パス」機能のようなものはありますか?
ありがとう。
したがって、あなたが探していると思うのはreturn
、命令型言語と同等のものです。
def do_something
foo
bar
return baz if quux
...
end
Haskell では、モナド チェーンは 1 つの大きな関数アプリケーションにすぎないため、これは機能しません。見栄えを良くする構文がありますが、次のように書くことができます
bind foo (bind bar (bind baz ...)))
途中で適用を「停止」することはできません。幸いなことに、本当に必要な場合は、Cont
モナドからの回答があります。callCC
. これは「call with current continuation」の略で、戻り値の表記を一般化したものです。あなたがSchemeを知っているなら、これはよく知られているはずです。
import Control.Monad.Cont
foo = callCC $ \escape -> do
foo
bar
when baz $ quux >>= escape
...
Control.Monad.Cont のドキュメントから恥知らずに盗んだ実行可能な例
whatsYourName name =
(`runCont` id) $ do
response <- callCC $ \exit -> do
validateName name exit
return $ "Welcome, " ++ name ++ "!"
return response
validateName name exit = do
when (null name) (exit "You forgot to tell me your name!")
そしてもちろん、これをIOなどに重ねることができるCont
トランスフォーマーContT
(これは絶対に気が狂います)があります。
補足として、callCC
は昔ながらの機能であり、まったく魔法のようなものではないため、実装は大きな課題です
だから、私が最初に想像した方法でそれを行う方法はないと思います。これは、命令型ループのブレーク関数に相当します。
しかし、Ingoの回答に基づいて、以下でも同じ効果が得られます。これは非常に簡単です(愚かな私)
doStuff x = if x > 5
then do
t <- getTingFromOutside
doHeavyHalculations t
else return ()
上記の例で「t」をテストする必要がある場合、それがどのように機能するかはわかりません...つまり、バインドされた値をテストし、そこからif決定を行う必要がある場合。
定義上、「モナドシーケンス」から抜け出すことはできません。「モナドシーケンス」は、他の値/関数に適用される1つの関数に他ならないことに注意してください。「モナド列」から命令型プログラムができると錯覚したとしても、これは (Haskell では) 正しくありません!
あなたができる唯一のことは、することですreturn ()
。この実用的な問題の解決策は、ここで既に名前が付けられています。しかし覚えておいてください: それはモナドから抜け出すことができるという錯覚を与えるだけです!