明らかにMonadConts はより制限されておりMonad、そのおかげでプレーンな sよりも強力callCCです。これは、そのインスタンスが少なくなり、より多くのことができることを意味します。
の定義されたインスタンスを見るとMonadCont、そこにリストされているすべてのものが 、または既存のインスタンスのいずれContかを必要とするように見えます。つまり、いくつかの or から開始する必要があり、特に に変えることはできません。ContTMonadContContContTIOMonadCont
ただし、コンテキストで使用するのは理にかなっていると思うので、以下を簡略化できます (公式の Hackage ページのcallCC例から調整):IO callCC
whatsYourName :: IO ()
whatsYourName = do
name <- getLine
let response = flip runCont id $ do
callCC $ \exit -> do
when (null name) (exit "You forgot to tell me your name!")
return $ "Welcome, " ++ name ++ "!"
print response
の中へ
whatsYourName' :: IO ()
whatsYourName' = do
name <- getLine
response <- callCC $ \exit -> do
when (null name) (exit "You forgot to tell me your name!")
return $ "Welcome, " ++ name ++ "!"
print response
callCCよりクリーンな方法で do ブロックで使用します。
当然のことながら、IOのインスタンスを作成するにMonadContは何らかの魔法が必要です。なぜなら、callCCforIOは「未来の計算で指定された関数を呼び出して、現実の世界で次に何が起こるかを指定する」ため、実際にこれが何を意味するかを知ることができるのはインタープリターまたはコンパイラーだけです。 . 一方、これがインポート可能であるという理論的な理由はわかりませんでした。これは、Scheme が既に長い間それを持っており、そのようなインスタンスを作成するために言語を変更する必要がまったくないためです。
考えられる問題
私が考えることができる 1 つの要因は、 is のセマンティクスがcallCC適切なクリーンアップの保証と競合することです。多くの言語は、適切なクリーンアップのために「try...finally」制御を提供しており、C++ のデストラクタもそれを保証しています。Haskell でそれが何であるかはわかりませんが、callCC利用できる場合はIO、それを使用して、クリーンアップが必要な関連するコンテキストから逃れることができます。そのため、Ruby で何が起こるかIOを確認できるように、sush 保証を提供することは不可能になります。
意見の議論
@jozefg からの回答は非常に優れています。ここに私の意見を書き留めておきたいと思います。
MonadContmtlから来ているのは本当です。しかし、それは、正しい定義がコンパイルモジュールのスコープ内にあり、設定されているunsafeCallCC場合、GHCまたは他のコンパイラがインスタンスを定義および定義できないという意味ではありません。MonadCont-XIOMonadCont例外の安全性については既に説明しましたが、それについて確信を持つのは難しいようです。しかし、私の意見では、Haskell には既に があり
unsafePerformIO、これは基本的に よりも安全ではありません。unsafeCallCCcallCCほとんどの場合、原因は強力すぎるため、可能な限り避ける必要があります。ただし、私の意見では、継続渡しスタイルを使用して遅延評価を明示的にすることができます。これにより、プログラムをよりよく理解し、最適化の可能性を見つけやすくなります。もちろんCPS は ではありませんMonadContが、それを使用して深くネストされた内部関数を do 表記に変換するのは自然なステップです。