在延迟序列内部是否实现延迟序列的差异 [英] Differences in whether realization of a lazy sequence inside of a lazy sequence occurs

查看:163
本文介绍了在延迟序列内部是否实现延迟序列的差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I wondered: What happens when you embed an expression that forces realization of a lazy sequence inside of an outer lazy sequence that's not realized?

取决于你如何创建外部延迟序列。如果外部序列来自 map ,内部序列被实现,如果外部序列来自 iterate 不。

Answer: It seems to depend on how you create the outer lazy sequence. If the outer sequence comes from map, the inner sequence is realized, and if the outer sequence comes for iterate, it's not.

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

Well, I'm pretty sure that that is not the right way to describe what happens below--I'm pretty sure that I'm not understanding something. Can someone explain?

(有一个怪癖,即 map 返回 LazySeq iterate 返回 $ 因此在下面的类和实现的测试中,我看看 iterate rest c $ c>。我不认为 map iterate 之间的区别与我的问题有关。)

(There is one quirk, which is that while map returns a LazySeq, iterate returns a Cons wrapped around a LazySeq. So in the tests for class and realization below, I look at the rest of the output of iterate. I don't believe that this difference between map and iterate has anything to do with my question.)

(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


推荐答案

如果强制实现内部序列的表达式是强制实现内部序列的表达式,那么这个表达式强制实现内部序列的实现。

"What happens when you embed an expression that forces realization of a lazy sequence inside of an outer lazy sequence that's not realized?"

If the expression which forces the realization of the inner sequence is in the unrealized portion of the outer sequence, then nothing.

不,它只取决于你的强制表达是在未实现部分。 map iterate 都不能实现任何尚未实现的东西。

No, it only depends on whether your forcing expression is in the unrealized portion. Neither map nor iterate realize anything that isn't already realized.

您需要考虑评估规则。你的例子的行为主要是渴望与懒惰评估的结果(Clojure是渴望的),并且只是与延迟序列切向相关。

You need to think through the evaluation rules. The behavior of your examples is mainly a consequence of eager vs. lazy evaluation (Clojure is eager) and is only tangentially related to lazy sequences.

第一个例子

首先考虑

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

第一个元素 def 表示使用特殊评估规则的特殊表单,但特别是当第二个参数供应它被评估。特别是,您正在评估

The first element def indicates a special form, with special evaluation rules, but in particular when a second argument is supplied it is evaluated. In particular, you are evaluating

(doa-twice three-vec)

此表单的评估是调用 doa两次三-vec ,看起来像下面的(替换后)

The evaluation of this form is an invocation of doa-twice on three-vec, which looks like the following (after substitution)

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

要评估这种形式,必须首先计算参数(Clojure评价)。特别是,您正在评估

To evaluate this form, the arguments have to be evaluated first (Clojure does eager evaluation). In particular, you are evaluating

(doall-once three-vec)

您的 doall-once 会使用 three-vec 。现在您正在评估

And your doall-once is invoked with argument three-vec. Now you are evaluating

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

这会在参数上调用 doall 惰性序列。 doall 通过定义强制实现该延迟序列。在实现过程中,你在 three-vec 的连续元素上调用 print-times-10-ret

This invokes doall on the argument, which is first evaluated to create a lazy-sequence. The doall forces realization of that lazy-sequence by definition. During that realization you are invoking print-times-10-ret on successive elements of three-vec, forcing realization of it along the way.

因此,您在这里看到的行为是热切评价的链接的结果。 Eager和惰性求值(Clojure是渴望的)不要与惰性和非惰性序列混淆(Clojure有两个)。

So the behavior your are seeing here is the consequence of the chaining of the eager evaluation. Eager vs lazy evaluation (Clojure is eager) is not to be confused with lazy vs. non-lazy sequences (Clojure has both).

strong>

Second Example

当您评估特殊的 def 表单

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

这导致第二个参数的评估

This causes evaluation of the second argument

(iterate doall-once three-vec)

评估此表单对其参数调用 iterate 。 Iterate创建 three-vec 和延迟序列的 Cons -cell。作为评价结果的 Cons -cell是,因此结束了渴望评价的链接的下降。此值由 def 设置为 doall-once-iter var的根绑定。这是 def 表单的评估结束。

Evaluation of this form invokes iterate on its arguments. Iterate creates a Cons-cell of three-vec and a lazy-sequence. That Cons-cell which is the result of the evaluation is a value, thus ending the descent of the chaining of eager evaluation here. This value is set as root binding of a doall-once-iter var by the def. This is the end of the evaluation of the def form.

(有一个怪癖,即当map返回一个LazySeq时,iterate返回一个包含在LazySeq中的Cons,所以在下面的类和实现的测试中,我不相信map和iterate之间的区别与我的问题有什么关系。)

正确,这个不起作用。如果 iterate 返回一个 LazySeq 对象,它仍然是一个

Correct, this does not play a role. If iterate returned a LazySeq object it would still be a value and stop the descent of the evaluation chain as above.

另请参阅计数实现如何计算序列的实现/非延迟部分,而不强制实现。或者, seq实现了?以回应我的想法也是您对Clojure Google群组的问题。

See also count-realized for how to count the realized/non-lazy portion of a sequence without forcing realization. Or, seq-realized? in response to what I think is also your question on the Clojure Google Group.

这篇关于在延迟序列内部是否实现延迟序列的差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆