8

cons は内部にある必要があります (lazy-seq ...)

(def lseq-in (lazy-seq (cons 1 (more-one))))

またはアウト?

(def lseq-out (cons 1 (lazy-seq (more-one))))

私は気づきました

(realized? lseq-in)
        ;;; ⇒ false

(realized? lseq-out)
        ;;; ⇒ <err>
        ;;;   ClassCastException clojure.lang.Cons cannot be cast to clojure.lang.IPending  clojure.core/realized? (core.clj:6773)

clojuredocs.orgのすべての例では、「out」を使用しています。

関連するトレードオフは何ですか?

4

2 に答える 2

8

(lazy-seq (cons ...))明確な理由がある場合にのみ、逸脱することは間違いありません。clojuredocs.org問題ありませんが、例はすべてコミュニティによって提供されており、「ドキュメント」とは呼びません。もちろん、それがどのように構築されているかの結果として、例は、問題の構造の使用方法を学び、助けたいと思っている人々によって書かれる傾向があるため、それらの多くは貧弱です. 代わりに、clojure.core のコード、またはその他の既知の適切なコードを参照します。

なぜこれをデフォルトにする必要があるのですか?の次の 2 つの実装を検討してくださいmap

(defn map1 [f coll]
  (when-let [s (seq coll)]
    (cons (f (first s))
          (lazy-seq (map1 f (rest coll))))))

(defn map2 [f coll]
  (lazy-seq
    (when-let [s (seq coll)]
      (cons (f (first s))
            (map2 f (rest coll))))))

を呼び出すと(map1 prn xs)、結果のマッピングされたシーケンスの要素を意図的に実現しなくても、 xs の要素が実現され、すぐに出力されます。map2一方、 はすぐに遅延シーケンスを返し、要素が要求されるまですべての作業を遅らせます。

于 2013-06-09T20:14:49.827 に答える
7

consinsideを使用lazy-seqすると、seq の最初の要素の式の評価が延期されます。外側でconsは、それはすぐに行われ、seq の「残りの」部分の構築のみが延期されます。(したがって(rest lseq-out)、遅延シーケンスになります。)

したがって、最初の要素の計算にコストがかかり、まったく必要ない場合は、cons内部に配置lazy-seqする方が理にかなっています。cons初期要素がレイジー seq プロデューサーに引数として提供される場合、外側で使用する方が理にかなっています(これは の場合clojure.core/iterateです)。そうでなければ、それほど大きな違いはありません。(開始時に遅延 seq オブジェクトを作成するオーバーヘッドは無視できます。)

Clojure 自体は両方のアプローチを使用します (ただし、ほとんどの場合lazy-seq、seq を生成する式全体をラップしますが、これは必ずしも で始まるとは限りませんcons)。

于 2013-06-09T20:14:20.700 に答える