是否在懒惰序列内部实现惰性序列的差异

时间:2014-04-17 15:12:30

标签: clojure lazy-evaluation

我想知道:当你嵌入一个强制在外部懒惰序列中实现懒惰序列的表达式时,会发生什么?

答案:这似乎取决于你如何创建外部懒惰序列。如果外部序列来自map,则内部序列被实现,如果外部序列来自iterate,则它不是。map

嗯,我很确定这不是描述下面发生的事情的正确方法 - 我很确定我不理解某些事情。有人可以解释一下吗?

(有一个怪癖,就是当LazySeq返回iterate时,Cons会返回LazySeq rest。{下面是对类和实现的测试,我看一下iterate输出的map。我不相信iterate(def three-vec (range 1 4)) (defn print-times-10-ret [x] (let [y (* 10 x)] (println "[" y "] " ) y)) (defn once [xs] (map print-times-10-ret xs)) (defn doall-once [xs] (doall (map print-times-10-ret xs))) (defn doa-twice [xs] (once (doall-once xs))) ; "doa" since only half doall-ed ;; Here the inner sequence seems to get realized: (def doa-twice-map (doa-twice three-vec)) ; printed output: ; [ 10 ] ; [ 20 ] ; [ 30 ] ;; Here we create a lazy sequence that will call doall-once when ;; realized, but nothing gets realized: (def doall-once-iter (iterate doall-once three-vec)) ; no printed output (class doa-twice-map) ; => clojure.lang.LazySeq ;; Note that this is not realized, even though the inner seq was realized (?): (realized? doa-twice-map) ; => false (class (rest doall-once-iter)) ; => clojure.lang.LazySeq (realized? (rest doall-once-iter)) ; => false 之间的这种区别有什么与我的问题有关。)

{{1}}

1 个答案:

答案 0 :(得分:7)

"当你嵌入一个强制在外部懒惰序列中实现懒惰序列的表达式时,会发生什么?"

如果强制实现内部序列的表达式在外部序列的未实现部分中,那么什么都没有。

" 答案:这似乎取决于你如何创建外部懒惰序列。如果外部序列来自map,那么内部序列就会实现,如果外部序列是迭代的,那就不是。"

不,它只取决于你的强制表达是否在未实现的部分。 mapiterate都没有意识到任何尚未实现的内容。

"描述"

下面发生的事情

您需要仔细考虑evaluation规则。你的例子的行为主要是渴望与懒惰评价的结果(Clojure非常渴望),并且只与懒惰序列相关。

第一个例子

首先考虑表格

(def doa-twice-map (doa-twice three-vec))

第一个元素def表示一个特殊形式,带有special evaluation个规则,但特别是当提供第二个参数时,它会被评估。特别是,您正在评估

(doa-twice three-vec)

此表单的评估是doa-twice three-vec的调用,如下所示(替换后)

(once (doall-once three-vec)))

要评估此表单,必须首先评估参数(Clojure急切评估)。特别是,您正在评估

(doall-once three-vec)

使用参数doall-once调用three-vec。现在你正在评估

(doall (map print-times-10-ret three-vec))

这将在参数上调用doall,首先对其进行求值以创建延迟序列。根据定义,doall强制实现该延迟序列。在那个实现过程中,你在print-times-10-ret的连续元素上调用three-vec,迫使它一路上实现它。

因此,您在此处看到的行为是热切评估的链接的结果。渴望与懒惰的评价(Clojure非常渴望)不要与懒惰与非懒惰的序列相混淆(Clojure都有)。

第二个例子

评估特殊def表单

(def doall-once-iter (iterate doall-once three-vec))

这导致评估第二个参数

(iterate doall-once three-vec)

对此表单的评估会在其参数上调用iterate。 Iterate创建Cons - three-vec的单元格和一个惰性序列。作为评估结果的Cons - 单元格是,从而结束了此处热切评估的链接下降。此值设置为doall-once-iter var与def的根绑定。这是对def表单的评估结束。

The Parenthetical

"(有一个怪癖,就是当map返回一个LazySeq时,iterate返回一个围绕LazySeq的Cons。所以在下面的类和实现的测试中,我看看剩下的迭代的输出。我不相信map和iterate之间的区别与我的问题有关。)"

正确,这不起作用。如果iterate返回LazySeq个对象,则它仍然是并停止评估链的下降,如上所述。

另请参阅count-realized,了解如何在不强制实现的情况下计算序列的已实现/非延迟部分。或者,seq-realized?回应我的想法也是您对Clojure Google Group的质疑。