遅延hGetContents。 バグまたは機能? (ハスケル)

私は長い間1つのトピックを心配していました。 それで、私は人々がこれについてどう思うかを話し、聞くことにしました。 hGetContents関数についてです。 ファイルを操作したことがある場合は、この関数がファイル(ストリーム)のコンテンツを返すことがわかります。 この関数を使用する典型的な例を次に示します。

import System.IO main = do file <- openFile "1.txt" ReadMode content <- hGetContents file print content hClose file -- :     
      
      







すべてが非常にありふれたものです-ファイルを開き、内容を読み、表示し、ファイルを閉じます。 hGetContentsの機能(またはHaskell機能)は、それが遅延していることです。 つまり、ファイルのデータはすぐに全体が読み込まれるのではなく、必要に応じて読み込まれます。 たとえば、そのようなプログラム

 import System.IO main = do file <- openFile "1.txt" ReadMode content <- hGetContents file print $ take 3 content hClose file -- :   3     
      
      





ファイルの最初の3文字のみを考慮します。

何と言ってもいい、素晴らしい機能です! 可変コンテンツ (ファイルコンテンツ)を操作することは非常に便利ですが、同時にHaskellは必要なものだけを取得し、それ以上のものは取得しないことを知っています。

次の例を考えてみましょう

 import System.IO main = do file <- openFile "1.txt" ReadMode content <- hGetContents file hClose file print content -- :   
      
      





ここで、最後の2行を再配置しました。 結果は、画面に表示される空の文字列になります。 なぜこれが起こったのですか? その理由は、ファイルが既に閉じられた後にファイルのコンテンツにアクセスしようとしているからです。 hGetContentsが呼び出されたときデータはどこにも読み込まれず、このファイルへのリンクが変数contentに保存されました。 そして、コンテンツcontentが必要になったときに、ファイルが既に閉じられていることがわかりました。

ファイルを閉じる前にコンテンツ変数を使用するだけでいいのです。



ここでの問題は、ファイルを閉じる前にHaskellにコンテンツ変数の計算を「取得」できないことです(誰かがメソッドを知っていれば、書きます)。 たとえば、ファイルを開き、内容を読み取り、構造を解析し、ファイルを閉じて、結果の構造を結果として表示する関数を記述する必要があります。

 {-# OPTIONS_GHC -XScopedTypeVariables #-} import System.IO parseFile :: (Read a) => String -> IO a parseFile fileName = do file <- openFile fileName ReadMode content <- hGetContents file rezult <- return $ read content hClose file return rezult main = do a :: Int <- parseFile "1.txt" print a --: 
      
      



これは基本的な例のようですが、機能しません。 同じ理由で。 ファイルの内容を読み取り関数に渡したという事実は、後で延期されたため、何も変わりませんでした。 そして、私たちがcontentで何をするにしても、これはHaskellがファイルからコンテンツを読むことを強制しません(もちろん、表示しない限り)。

もちろん、プログラム全体をopenFilehCloseの間に置くこともできますが、ファイルから内容を読み取り、それを修正して同じファイルに書き込む必要がある場合はどうでしょうか。



私は長い間この例を考えていましたが、「ここで何かがおかしい」という気持ちは私を一人にさせませんでした。 それはHaskellの純度に違反していませんか。 基本的に正しいプログラムを作成しましたが、正しい結果が得られません。 彼はいつこの変数に目を向けるのか、そして彼はボンネットの下で何をするのか、私は何を考えるべきですか? これはHaskellではありません。式には申し訳ありませんが、ある種のC ++です。

その結果、この「機能」は機能ではなくバグであるという結論に達しました。 私があなたを納得させていないなら、ここにいくつかの理由があります:





なぜ私はこれすべてですか? 誤解しないでください。 私はHaskellが大好きです。 その純度、怠iness、機能性など、言葉では表現できないものがたくさんあります。 突然、以前考えていたほど「きれい」ではないことがわかりました。 この機能は良いように思える複雑な感覚がありましたが、どういうわけかそれは「汚い」ものになりました。

たぶん私はただの妄想です。 あなたの意見、バグまたは機能を聞きたいですか?



All Articles