0

System.TimeoutHaskell の練習をして、よく知らない領域を調べていますが、 と を混合しているときに得られる動作を理解できませんでしたSystem.IO.Unsafe

でストリームを怠惰に読み取り、getContents純粋な関数でフィルタリングし、結果を出力しています。典型的なフィルターは次のようになります。

import Data.List(break)
import System.Timeout(timeout)
import System.IO.Unsafe(unsafePerformIO)

main = do
    text <- getContents 
    putStr $ aFilter text
aFilter text = h ++ t where
    (h, t) = getUntil "\n" text
getUntil separator text = break (\x -> (separator!!0) == x) text

そして、そのようなフィルターを使用すると、プログラムは期待どおりにすべての stdin を読み取り、stdout に出力します。しかし、私が次のようなことをすると:

aFilter text = result where
    l = consumeWithTimeout (getUntil "\n" text)
    result = case l of
        Nothing -> "Timeout!\n"
        Just (h, t) -> h ++ t

consumeWithTimeout (x, y) = unsafePerformIO $! timeout 6 $! deepseq x (return (x, y))

私のプログラムは即座にタイムアウトし、「Timeout!」を出力すると思います。メッセージを表示して閉じます。代わりに、そこでハングして、入力を待ちます。

timeout関数がプログラムの起動時に評価されると考えるのは間違っていますか? 戻り値の一部をすぐに stdout に書き込み、行を入力するたびにソフトウェアが反応するため、そうなると思います。unsafePerformIO関数にある種の怠惰を挿入していますか? それとも、の内部に怠惰を挿入していSystem.Timeoutますか?

4

2 に答える 2

3

その理由は、orreturn $! (x, y)を厳密に評価していないからです。タプル コンストラクターのみを評価し、必ずしもそのフィールドおよびフィールドを評価するとは限りません。xyxy

したがって、プログラムで何が起こるかは、実際にandreturn $! (x, y)を評価しようとせずにすぐに成功することです。次に、パーツは評価を開始し、最終的に入力のブロックを開始します。xyh ++ th

ちなみに、これが を使用すべきではない理由ですunsafePerformIO。効果が実際にいつ発生するかを簡単に判断することはできません。

于 2014-05-18T21:29:27.807 に答える
0

私は期待するだろう

timeout 6 $! return $! (x, y)

通常のワークロードでタイムアウトをトリガーしないようにします。上記のコードは、 と の評価を強制しませxy。ここで使用evaluateすると役立つかもしれません。

さらに、unsafePerformIOこのタスクに使用するのはかなりやり過ぎに見えます。使用unsafePerformIOは、最後の手段としてのみ行う必要があります。

于 2014-05-18T18:59:38.260 に答える