2012-03-02 19 views
5

最近、私はWaterloo CCCをやりました。私はHaskellがこれらのタイプの質問に答えるのに最適な言語だと感じます。私はまだそれを学んでいます。私は入力と少し苦労しています。ここで Haskell:行単位でファイルを読む

は、私が使用しているものです:あなたが見ることができるように、このプログラムは j1.hsと呼ばれるにコンパイルされている場合、私は、コマンドライン指定したファイルパスから、あるいは例えば j1.inから読んでいる

import IO 
import System.Environment 
import System.FilePath 

… 

main = do 
    name <- getProgName 
    args <- getArgs 
    input <- readFile $ 
     if not (null args) 
      then head args 
      else dropExtension name ++ ".in" 
    let (k:code:_) = lines input 
    putStrLn $ decode (read k) code 

j1

私はファイルの最初の2行だけに興味があるので、パターンマッチングを使用してこれらの行を取得し、kcodeにバインドしました。そして私は整数としてkを読んで、私が出力する私のdecode関数にコード文字列を渡します。

readFileがファイル全体をメモリにロードしているかどうかは不思議ですが、それは問題になります。しかし、私は考え始めました。おそらくハスケルは怠惰なので、最初の2行を読むのはそれだけです。後でそれが求められるからです。私は正しい?

また、そのコードサンプルで、よりよくまたはもっと慣用的なものがあれば教えてください。

答えて

8

documentation for readFileは言う:

readFile関数は、ファイルを読み込み、ファイルの内容を文字列として返します。ファイルは、getContentsのように、必要に応じて遅延読み込みされます。

だから、ファイルの最初の2行だけを読む必要があります(バッファリングとは、おそらく舞台裏でもっと読むでしょう)。しかし、これは特にreadFileのプロパティであり、一般的なHaskell入出力関数のすべてではありません。

レイジーI/OはI/O重いプログラム(ウェブサーバーなど)にとっては悪い考えですが、多くのI/Oを実行しない単純なプログラムではうまく動作します。

+0

チュートリアル 'hSetBuffering stdin LineBuffering'では、入力が一度に1行だけ入力されるため、stdinに使用されていました。ファイル入力に相当するものはありますか?それを使用することが理にかなっているのであれば、それは早すぎる最適化と見なされますか? – mk12

+3

本質的に怠惰なI/Oは、それが簡単な場合にのみ有用であるというあなたの意見に同意しません。 I/Oが重い設定の遅延I/Oの非常に便利な機能の例は、デフォルトではデータ処理がインプレースされているため、大量のデータに対して非常に効率的です。 – amindfv

+0

@amindfv:彼は大きなプログラムのために怠惰なI/Oが無駄だとは言わないが、それは_bad_だと言う。彼が意味することは、遅延IOは、大きくて複雑なプログラムで修正するのが難しいリソースリーク(ここではファイルが最後まで読み込まれないため、決して閉じられない)につながることが多いということです。ストリーミングのより基本的な解決策(イテレータテや最近のコンジットなど)は、より優れた制御を提供するため、望ましいものになります。 – Jedai

6

はい、readFileは遅延です。明示したい場合は、次のように使用します。

import Control.Monad (replicateM) 
import System.IO 

readLines n f = withFile f ReadMode $ replicateM n . hGetLine 

-- in main 
    (k:code:_) <- readLines 2 filename 

これにより、ファイルができるだけ早く閉じられるようになります。

しかし、あなたがやったやり方はうまくいきます。

3

readFileは、ファイルを遅延読み込みするので、ファイル全体を使用しない限り、ファイル全体をメモリに読み込むことはありません。最初の2行はブロック単位で読み込まれるため、通常は正確には読み込まれませんが、2行目の改行を見つけるために必要なだけ多くのブロックが読み込まれます。

2

ハスケルのI/Oは、通常は怠惰ではありません。しかし、readFileの機能は、具体的にはです。

他は同じことを言っています。まだ誰も指摘していないことは、開いたファイルが、プログラムが終了するかガベージコレクタが実行されるまで閉じられないということです。つまり、OSファイルハンドルが必要以上に長く開いている可能性があります。あなたのプログラムではおそらく大したことではありません。しかし、より複雑なプロジェクトでは、それは可能性があります。

関連する問題