web-dev-qa-db-ja.com

Clojureでレイジーシーケンスを非レイジーに変換する方法

Clojureで以下を試してみました。非遅延シーケンスのクラスが返されることを期待しています。

(.getClass (doall (take 3 (repeatedly Rand))))

ただし、これは依然としてclojure.lang.LazySeqを返します。私の推測では、doallはシーケンス全体を評価しますが、メモ化にはまだ有用なので元のシーケンスを返します。

では、怠zyなシーケンスから非遅延シーケンスを作成する慣用的な手段は何ですか?

90
Tim Clemons

doallで十分です。 seqのタイプがLazySeqであるからといって、評価が保留されているわけではありません。レイジーシーケンスは結果をキャッシュするので、必要なのは、レイジーシーケンスを1回(doallが行うように)歩いてすべて強制的に実行し、それによってレイジーでないようにすることです。 seqはnotコレクション全体を強制的に評価します。

150
Rich Hickey

これは、ある程度分類の問題です。 レイジーシーケンスは、シーケンスの一種です asはリスト、ベクター、またはマップです。したがって、答えはもちろん「取得する非遅延シーケンスの種類によって異なります。
次から選択してください:

  • 元の遅延(完全に評価された)遅延シーケンス(doall ... )
  • 順次アクセスのリスト(apply list (my-lazy-seq)) OR (into () ...)
  • 後でランダムアクセスするためのベクトル(vec (my-lazy-seq))
  • 特別な目的がある場合は、マップまたはセット。

必要なほとんどのスイートにどんなタイプのシーケンスでも使用できます。

66
Arthur Ulfeldt

この金持ちの男は彼のclojureを知っているようで、絶対に正しいです。
Buthこのコードスニペットは、例を使用すると、この質問を補足するのに役立つかもしれません。

=> (realized? (take 3 (repeatedly Rand))) 
false
=> (realized? (doall (take 3 (repeatedly Rand)))) 
true

確かにtypeは変更されていませんが、realizationは変更されています

21
Peter

これにつまずいた blogdoallが再帰的ではないという投稿。そのために、私は投稿の最初のコメントがトリックをしたことを発見しました。以下の線に沿ったもの:

(use 'closure.walk)
(postwalk identity nested-lazy-thing)

これは、mapの入れ子になったアプリケーションのいくつかの評価を強制してエラー条件を強制したい単体テストで役立ちました。

7
leeor
(.getClass (into '() (take 3 (repeatedly Rand))))
5
stupito