8

私は現在、遅延シーケンスに関するセクションで次のように述べているO'reilly Clojureプログラミングの本を読んでいます:

(非常にまれですが) 遅延シーケンスがその長さを知っている可能性があるため、その内容を認識せずに count の結果としてそれを返します。

私の質問は、これがどのように行われ、なぜそれほどまれなのかということです.

残念ながら、本はこのセクションでこれらのことを指定していません. 個人的には、実現前に遅延シーケンスの長さを知ることは非常に役立つと思います。たとえば、同じページでは、関数を使用して処理されるファイルの遅延シーケンスの例mapです シーケンスを実現する前に、いくつのファイルを処理できるかを知っておくとよいでしょう。

4

2 に答える 2

9

soulcheck の answerに触発されたように、固定サイズのコレクションに対する高価な関数の遅延ではあるがカウントされたマップを次に示します。

(defn foo [s f] 
  (let [c (count s), res (map f s)] 
    (reify 
      clojure.lang.ISeq 
        (seq [_] res) 
      clojure.lang.Counted 
        (count [_] c) 
      clojure.lang.IPending 
        (isRealized [_] (realized? res)))))


(def bar (foo (range 5) (fn [x] (Thread/sleep 1000) (inc x))))

(time (count bar))
;=> "Elapsed time: 0.016848 msecs"
;    5

(realized? bar)
;=> false


(time (into [] bar))
;=> "Elapsed time: 4996.398302 msecs"
;   [1 2 3 4 5]

(realized? bar)
;=> true

(time (into [] bar))
;=> "Elapsed time: 0.042735 msecs"
;   [1 2 3 4 5]
于 2013-08-27T18:08:33.540 に答える
7

通常、サイズを調べる方法は他にもあるためだと思います。

私が今考えることができる唯一のシーケンス実装は、既知のサイズのコレクションに対する高価な関数/手順のある種のマップです。

単純な実装では、基礎となるコレクションのサイズを返しますが、遅延シーケンスの要素の実現 (したがって、高価な部分の実行) は必要になるまで延期します。

その場合、事前にマップされるコレクションのサイズがわかっているので、lazy-seq サイズの代わりにそれを使用できます。

便利な場合もあるので、実装するのは不可能ではありませんが、必要になることはめったにないと思います。

于 2013-08-27T17:32:57.807 に答える