24

ここに考えるべき食べ物があります。

モナドコードを書くとき、モナドは実行された操作に順序を課します。たとえば、IOモナドに書き込む場合:

do a <- doSomething
   b <- doSomethingElse
   return (a + b)

私はdoSomething前に実行されることを知っていますdoSomethingElse

ここで、Cのような言語の同等のコードを考えてみましょう。

return (doSomething() + doSomethingElse());

Cのセマンティクスは、これら2つの関数呼び出しが評価される順序を実際には指定しないため、コンパイラーは自由に物事を自由に移動できます。

私の質問はこれです:この評価順序も未定義のままにするHaskellでモナディックコードをどのように書くのですか?理想的には、コンパイラのオプティマイザがコードを調べて動き始めたときに、いくつかのメリットを享受できます。

仕事を成し遂げることができないが、正しい「精神」にあるいくつかの可能なテクニックはここにあります:

  • 機能的なスタイルでコードを記述します。つまり、モナディック呼び出しを記述plus doSomething doSomethingElseしてplusスケジュールします。欠点:モナディックアクションの結果の共有を失い、plusそれでも物事がいつ評価されるかについて決定を下します。
  • 遅延IOを使用します。つまりunsafeInterleaveIO、評価の遅延を要求するようにスケジューリングを延期します。しかし、怠惰は、順序が定義されていない厳密なものとは異なります。特に、すべてのモナディックアクションを実行する必要があります。
  • レイジーIO、すべての引数をすぐにシーケンスすることと組み合わせる。特に、seq順序の制約を課しません。

この意味で、私は単調な順序付けよりも柔軟性がありますが、完全な怠惰よりも柔軟性が低いものが必要です。

4

3 に答える 3

16

モナドコードをオーバーシーケンシャル化するこの問題は、「可換モナド問題」として知られています。

可換モナドは、アクションの順序に違いがない(通勤する)モナドです。つまり、次のコードの場合です。

do a <- f x
   b <- g y
   m a b

と同じです:

do b <- g y
   a <- f x
   m a b

通勤するモナドはたくさんあります(例Maybe:)Random。モナドが可換である場合、その中でキャプチャされた操作は、たとえば、並列に計算できます。とても便利です!

しかし、通勤するモナドの構文はよくありませんが多くの人がそのようなことを求めていますが、それはまだ未解決の研究問題です。

余談ですが、アプリケーションファンクターは計算を並べ替える自由を与えてくれますが、bind(たとえばliftM2showの提案として)の概念をあきらめる必要があります。

于 2011-05-05T17:09:27.487 に答える
9

これは非常に汚いハックですが、私にはうまくいくはずです。

{-# OPTIONS_GHC -fglasgow-exts #-}
{-# LANGUAGE MagicHash #-}
module Unorder where
import GHC.Types

unorder :: IO a -> IO b -> IO (a, b)
unorder (IO f) (IO g) = IO $ \rw# ->
           let (# _, x #) = f rw#
               (# _, y #) = g rw#
           in (# rw# , (x,y) #)

これは非決定論をコンパイラーの手に委ねるため、制御フローの問題(つまり例外)に関しても「正しく」(つまり非決定論的に)動作する必要があります。

一方、トークンをいじることで利用できる距離での不気味なアクションに実際に依存しているため、Stateなど のほとんどの標準的なモナドと同じトリックを引き出すことはできません。正しい動作を得るには、オプティマイザーが利用できる注釈が必要です。これは、2つの同等ではない選択肢の間で非決定論的な選択を行っても問題がないことを示しています。Either aRealWorld

于 2011-05-05T17:22:49.667 に答える
3

Cのセマンティクスは、これら2つの関数呼び出しが評価される順序を実際には指定しないため、コンパイラーは自由に物事を自由に移動できます。

しかしdoSomething()、の動作を変更する副作用が発生した場合はどうなりdoSomethingElse()ますか?コンパイラーに注文を混乱させたいですか?(ヒント:いいえ)あなたがモナドにいるという事実は、そのような場合があることを示唆しています。「結果の共有を失う」というあなたのメモもこれを示唆しています。

ただし、モナディックは必ずしもシーケンスを意味するわけではないことに注意してください。それはあなたが正確に説明していることではありませんが、あなたはあなたがあなたの行動を並行して実行することを可能にするパーモナドに興味があるかもしれません。

コンパイラが魔法のように順序を最適化できるように、順序を未定義のままにしておくことに関心があります。おそらく代わりに、Parモナドのようなものを使用して依存関係を示し(必然的に他の事柄よりも先に発生する必要があるものもあります)、残りを並行して実行する必要があります。

補足:ハスケルreturnをCのようなものと混同しないでくださいreturn

于 2011-05-05T15:05:46.843 に答える