継承したいくつかの反復 Java ライブラリ コードから Clojure seq を作成しようとしています。基本的に、Java コードが行うことは、パーサーを使用してファイルからレコードを読み取り、それらのレコードをプロセッサに送信して、結果の ArrayList を返すことです。Java では、これは parser.readData() を呼び出してから parser.getRecord() を呼び出してレコードを取得し、そのレコードを processor.processRecord() に渡すことによって行われます。parser.readData() を呼び出すたびに、単一のレコードが返されるか、それ以上レコードがない場合は null が返されます。Java ではかなり一般的なパターン。
そこで、パーサーから次のレコードを取得する次のレコード関数を Clojure で作成しました。
(defn next-record
"Get the next record from the parser and process it."
[parser processor]
(let [datamap (.readData parser)
row (.getRecord parser datamap)]
(if (nil? row)
nil
(.processRecord processor row 100))))
次に、この関数を呼び出して、レコードを Clojure seq (できれば遅延 seq) に蓄積します。したがって、レコードが多すぎない限り、うまく機能する私の最初の試みは次のとおりです。
(defn datamap-seq
"Returns a lazy seq of the records using the given parser and processor"
[parser processor]
(lazy-seq
(when-let [records (next-record parser processor)]
(cons records (datamap-seq parser processor)))))
パーサーとプロセッサーを作成し、(take 5 (datamap-seq parser processor)) のようなことを行うと、レイジー seq が得られます。そして、予想どおり、その seq の (最初の) 取得は 1 つの要素のみを認識し、count を実行するとそれらすべてが認識されます。
もちろん、多くのレコードがある場合、StackOverflowException が発生します。そこで、私の次の試みは loop-recur を使って同じことをすることでした。
(defn datamap-seq
"Returns a lazy seq of the records using the given parser and processor"
[parser processor]
(lazy-seq
(loop [records (seq '())]
(if-let [record (next-record parser processor)]
(recur (cons record records))
records))))
これを同じ方法で使用し、(def results (datamap-seq parser processor)) を使用して定義すると、遅延 seq が得られ、要素が認識されません。ただし、(最初の結果)のようなことをするとすぐに、seq全体の実現が強制されます。
loop-recur を使用して2番目の関数でどこが間違っているのかを理解してくれる人はいますか?
アップデート:
例外のスタック トレースを詳しく調べたところ、Java クラスの 1 つからスタック オーバーフロー例外がスローされています。しかし、このような datamap-seq 関数がある場合にのみ発生します (上に投稿したものは実際に機能します)。
(defn datamap-seq
"Returns a lazy seq of the records using the given parser and processor"
[parser processor]
(lazy-seq
(when-let [records (next-record parser processor)]
(cons records (remove empty? (datamap-seq parser processor))))))
その削除が問題を引き起こす理由はよくわかりませんが、この関数から削除すると、すべて正常に機能します(空のリストの削除を別の場所で行っています)。