3

hGetContentsは、ファイル ハンドルから読み取るために純粋に機能的なコードで使用できる遅延 String オブジェクトを返します。この遅延文字列の読み取り中に I/O 例外が発生した場合、基になるファイル ハンドルはサイレントに閉じられ、遅延文字列に追加の文字は追加されません。

この I/O 例外はどのように検出できますか?

具体的な例として、次のプログラムを考えてみましょう。

import System.IO    -- for stdin

lengthOfFirstLine :: String -> Int
lengthOfFirstLine "" = 0
lengthOfFirstLine s  = (length . head . lines) s

main :: IO ()
main = do
    lazyStdin <- hGetContents stdin
    print (lengthOfFirstLine lazyStdin)

ファイルの最初の行の読み取り中に例外が発生した場合、このプログラムは I/O 例外が発生するまでの文字数を出力します。代わりに、適切な I/O 例外でプログラムをクラッシュさせたいのです。このプログラムをどのように変更して、その動作をさせることができますか?

編集: hGetContents の実装を詳しく調べると、I/O 例外は無視されず、純粋な機能コードの呼び出しから、たまたま評価をトリガーした IO コードにバブル アップし、それを処理する機会があるように見えます。(純粋な機能コードが例外を発生させる可能性があることを以前は知りませんでした。) したがって、この質問は誤解です。

余談ですが、この例外的な振る舞いが経験的に検証されれば最高です。残念ながら、低レベルの I/O エラーをシミュレートすることは困難です。

4

2 に答える 2

5

Lazy IOは多くの Haskeller によって落とし穴であると考えられているため、避けるように勧められています。あなたのケースは、その理由をカラフルに説明しています。

function非遅延代替手段がありhGetContentsます。で動作しますTextText、一般的には の代替としても好まれStringます。便宜上、StringText: basic-preludeおよびclassy-preludeに置き換えたモダンなプレリュードがあります。

于 2013-04-27T21:55:50.227 に答える
1

余談ですが、この例外的な振る舞いが経験的に検証されれば最高です。残念ながら、低レベルの I/O エラーをシミュレートすることは困難です。

私は同じことについて疑問に思っていましたが、この古い質問を見つけて、実験を行うことにしました.

Windows でこの小さなプログラムを実行しました。このプログラムは、接続をリッスンし、遅延して読み取ります。

import System.IO
import Network
import Control.Concurrent

main :: IO ()
main = withSocketsDo (do
    socket <- listenOn (PortNumber 19999)
    print "created socket"
    (h,_,_) <- accept socket
    print "accepted connection"
    contents <- hGetContents h
    print contents)

Linux マシンから、次を使用して接続を開きましたnc

nc -v mymachine 19999
Connection to mymachine 19999 port [tcp/*] succeeded!

次に、Windows Sysinternal のTCPViewユーティリティを使用して、接続を強制的に閉じました。結果は次のとおりです。

Main.exe: <socket: 348>: hGetContents: failed (Unknown error)

I/O 例外が発生するようです。

hGetContentsさらなる実験:呼び出しの直後に遅延を追加しました:

...
contents <- hGetContents h
threadDelay (60 * 1000^2)   
print contents)

printこの変更により、遅延 I/O のおかげで、実行されるまで実際には何も読み取られないため、接続を強制終了してもすぐに例外が発生しなくなりました。

于 2015-11-29T16:25:52.423 に答える