2012-04-03 9 views
3

私はこの関数を書いていますが、その戻り値は何ですか?この関数の戻り値は何ですか?

(defn read-data [file] 
    (let [code (subs (.getName file) 0 3)] 
    (with-open [rdr (clojure.java.io/reader file)] 
     (drop 1 (line-seq rdr))))) 

(def d (read-data "data.db")) 

今までは問題ありません。しかし、私はこれを印刷したいとき。

(clojure.pprint/pprint d) 

私は、例外が発生しました:

Exception in thread "main" java.lang.RuntimeException: java.io.IOException: Stream closed 

は、私は間違って何を、混乱?戻り値はリストではありませんか?初心者としてこのような状況でデバッグする方法は?

ありがとうございます!

答えて

3

問題は、line-seqが遅延していることと、評価されるまでに読者が閉じていることです。

つまり、with-openの範囲内ですべての行を読む必要があります。 1つの選択肢は、doallを使用して、line-seqの完全な評価を強制することです。

(drop 1 (doall (line-seq rdr))) 

このアプローチの潜在的な問題は、ファイルが使用可能なメモリよりも大きい場合にOutOfMemoryErrorが発生することです。だから、あなたが達成しようとしていることに応じて、他にメモリを必要としないソリューションが少なくなるかもしれません。

+0

あなたが最初のものである:

(defn line-seq2 [^java.io.BufferedReader rdr] (if-let [line (.readLine rdr)] (cons line (lazy-seq (line-seq2 rdr))) (.close rdr))) (defn my-reader [file] (let [lines (line-seq (clojure.java.io/reader file))] (fn [] lines))) (def d (my-reader "data.db")) 

今、変数 "d" を機能です。ありがとう! – Kane

1
(drop 1 (line-seq rdr)) 

この行は、シーケンス、つまりレイジーまたはストリームを返します。だから、基本的には、この行が実行されたときにファイルリーダーrdrは実際には読み取られませんが、printメソッドでこのシーケンスにアクセスしようとすると、rdrはline-seq関数によって読み取られますが、with-openを使用しているので、実行フローがwith-openから外れると閉じます。

レイジーシーケンスを作成するたびに評価するようにするには、doallを参照してください。私は、一般的なFPでの怠惰やClojureでの遅延評価についての理解を深めておくことをお勧めします。

2

は一例として、あなたが閉鎖し、改変された "行-seqの" オートクローズ読者のために使用することができます。

user> (drop 1 (d)) 
=> ... file body except first line ... 
関連する問題