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“。
涉及的权衡是什么?
发布于 2013-06-10 04:14:50
您肯定希望(lazy-seq (cons ...))作为您的默认设置,只有在您有明确的理由时才会偏离。clojuredocs.org很好,但示例都是社区提供的,我不会称它们为“文档”。当然,它的构建方式的一个后果是,这些示例往往是由刚刚学会如何使用所讨论的构造并希望提供帮助的人编写的,所以他们中的许多人都很差。我会参考clojure.core中的代码,或者其他已知良好的代码。
为什么这应该是默认的?考虑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-10 04:14:21
在lazy-seq中使用cons时,seq的第一个元素的表达式的求值会被延迟;而在cons中,表达式的计算会立即完成,并且只会延迟seq的"rest“部分的构造。(所以(rest lseq-out)将是一个懒惰的序列。)
因此,如果计算第一个元素的成本很高,而且可能根本不需要它,那么将cons放在lazy-seq中更有意义。如果将初始元素作为参数提供给lazy seq生成器,那么在外部使用cons可能更有意义(clojure.core/iterate就是这种情况)。否则,这不会有太大的不同。(在开始时创建惰性seq对象的开销可以忽略不计。)
Clojure本身使用这两种方法(尽管在大多数情况下,lazy-seq包装了整个seq生成表达式,不一定以cons开头)。
https://stackoverflow.com/questions/17012266
复制相似问题