3

明らかに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 からの回答は非常に優れています。ここに私の意見を書き留めておきたいと思います。

  1. MonadContmtlから来ているのは本当です。しかし、それは、正しい定義がコンパイルモジュールのスコープ内にあり、設定されているunsafeCallCC場合、GHCまたは他のコンパイラがインスタンスを定義および定義できないという意味ではありません。MonadCont-XIOMonadCont

  2. 例外の安全性については既に説明しましたが、それについて確信を持つのは難しいようです。しかし、私の意見では、Haskell には既に がありunsafePerformIO、これは基本的に よりも安全ではありません。unsafeCallCC

  3. callCCほとんどの場合、原因は強力すぎるため、可能な限り避ける必要があります。ただし、私の意見では、継続渡しスタイルを使用して遅延評価を明示的にすることができます。これにより、プログラムをよりよく理解し、最適化の可能性を見つけやすくなります。もちろんCPS は ではありませんMonadContが、それを使用して深くネストされた内部関数を do 表記に変換するのは自然なステップです。

4

4 に答える 4

9

これは悪い考えだと思います。まず第一にMonadCont、MTLにあります。GHC はそれについて何も知りません。これは、コンパイラをサードパーティのライブラリに依存させることを意味します。

第二にcallCC、主にコードについての推論を面倒にするため、一部の非常に有名なSchemersの間でも人気がありません! goto推論するのが難しいのとほぼ同じように。特に Haskell では、どこに関心を持たなければならないか

  1. 例外安全ですか?(これはすでにかなり難しい)
  2. callCC安全ですか?

最後に、それは必要ありません。継続と IO を使用する場合は、 を使用するとContT IO、まったく同じように強力です。ただし、 などのそれほど強力でないものに置き換えることができることはほぼ保証されていますmonad-prompt。継続は大ハンマーであり、10 回中 9 回callCCは強力すぎて、高次関数と怠惰の組み合わせを使用してより快適に表現できます。

例として、 の典型的な使用法の 1 つはcallCC例外のようなものを実装することですが、Haskell ではモナドを使用できます :) (高階関数と遅延に依存します)。

本質的に、あなたの提案は複雑さを増し、MTL をベースにマージすることを意味しますliftIO

RE編集

  1. 確かにこれを行うことができますが、もちろんそれはインスタンスではありませんMonadCont:)
  2. これは少し異なり、unsafePerformIO実行方法や実行時期が保証されていないため、副作用が他の人に見えないようにするためのものです。

    これが の場合であれば、!callCCIOを使用できます。Cont

  3. 継続渡しスタイルは便利ですConT r IO。これは私にとって棺桶の最大の釘です。困難で潜在的に安全でないコンパイラハックよりも既存のライブラリを使用するだけで、このアイデアには何の利点もありません。

于 2013-11-08T05:20:07.663 に答える
1

call/cc はどの言語にとっても不適切な機能であるため、答えは NO です。call/cc は非常に長い間 Scheme にありましたが、call/cc が優れた言語機能であるとは限りません。Scheme で call/cc を使用した経験から、これは言語機能として不適切であることがわかりました。一方、dynamic-wind を使用すると、標準の call/cc イディオムは遅くなります。これらすべての欠点は、 http://okmij.org/ftp/continuations/against-callcc.htmlに、サポート コードやその他の証拠 とともに列挙されています。

継続渡しスタイルには多くの利点があることに同意します。実際、Haskell コードをモナディック スタイルで記述するときは、正確に CPS を使用します。実際、単純なネストされた関数の呼び出しを考えてみましょうputChar (getChar ())。CPS では次のように記述します。

 getCharK :: () -> (Char -> w) -> w
 putCharK :: Char -> (() -> w) -> w

 gp :: (() -> w) -> w
 gp = \k -> getCharK () (\c -> putCharK c k)

そしてここで、モナドの getM と putM (いくつかのモナド M) に対して同じネストされた呼び出しをどのように記述するかを示します。

getM :: () -> M Char
putM :: Char -> M ()

gpM :: M ()
gpM =  getM () `bind` (\c -> putM c)

ここで、バインドが次のように定義されている場合

bind m f = \k -> m (\x -> (f x) k)

その場合、モナドのネストされた関数の適用は、コードの CPS バージョンと同じです。bind の定義でM をContT w IOand および newtype ラッパー ContT/runContT に置き換えると ( (>>=)ContT w IO モナドになります)、モナドの例は Haskell で機能します。Haskell では、すでに CPS でコードを記述できます。do 表記により、非常に便利になります。

于 2013-11-23T03:50:08.613 に答える
0

ドキュメントには次のように記載されています。

他の言語で継続を必要とする多くのアルゴリズムは、Haskell の遅延セマンティクスにより、Haskell では継続を必要としません。Continuation モナドを乱用すると、理解や保守が不可能なコードが生成される可能性があります

多分これが主な理由だと思います。

于 2013-11-08T05:14:37.647 に答える