5

これを実行すると、期待どおりに機能します。

(defn long-seq [n]
  (lazy-seq (cons 
             (list n {:somekey (* n 2)})
             (long-seq (+ n 1)))))
(take 3 (long-seq 3))
; => ((3 {:somekey 6}) (4 {:somekey 8}) (5 {:somekey 10}))

しかし、私はベクトルで同じことをしたいと思います:

(defn long-seq-vec [n]
  (lazy-seq (into 
             (vector (list n {:somekey (* n 2)}))
             (long-seq-vec (+ n 1)))))
(take 3 (long-seq-vec 3))

これにより、スタックオーバーフローが発生します。なんで?

4

1 に答える 1

8

主な理由は、ベクトルが怠惰ではないことです。そのため、into呼び出しは、によって生成された再帰シーケンスを貪欲に消費long-seq-vecし、スタックオーバーフローを引き起こします。これの当然の結果として、無限のベクトルを作成することはできません(一般に、無限のデータ構造を作成できるのは、レイジーまたはサイクリックの場合のみです)。

最初の例で機能するのconsは、怠惰なシーケンスの前でコンスするときに怠惰に振る舞うことが非常に喜ばしいため、シーケンスが無限になる可能性があるためです。

あなたが実際にベクトルの無限のシーケンスを望んでいると仮定すると、私は次のようなものを提案します:

(defn long-seq-vec [n]
  (lazy-seq (cons 
              (vector n {:somekey (* n 2)})
              (long-seq-vec (+ n 1)))))

(take 3 (long-seq-vec 3))

=> ([3 {:somekey 6}] [4 {:somekey 8}] [5 {:somekey 10}])

または、代わりに、forそれ自体が怠惰なものを使用することもできます。

(defn long-seq-vec [n]
  (for [x (iterate inc n)]
    (vector x {:somekey (* x 2)})))

lazy-seq/ボイラープレートを回避し、再帰を回避し、関数の機能を少し明確に表現できるので、これが好きconsです...必要に応じて、もう少し「宣言型」になります。map同様の方法で使用することもできます。

于 2012-08-31T00:44:22.147 に答える