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

Clojure 是否在惰性序列内部实现惰性序列的差异,clojure,lazy-evaluation,Clojure,Lazy Evaluation,我想知道:当您嵌入一个表达式,强制在未实现的外部惰性序列中实现惰性序列时,会发生什么 答:这似乎取决于如何创建外部惰性序列。如果外部序列来自map,则实现内部序列,如果外部序列来自iterate,则不是 嗯,我很确定这不是描述下面发生的事情的正确方式——我很确定我没有理解一些事情。有人能解释一下吗 (有一个怪癖,map返回一个LazySeq,iterate返回一个Cons围绕LazySeq。因此在下面的类和实现测试中,我看了iterate输出的rest。我不相信和之间的差异e> 映射和迭代与我的

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

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

嗯,我很确定这不是描述下面发生的事情的正确方式——我很确定我没有理解一些事情。有人能解释一下吗

(有一个怪癖,
map
返回一个
LazySeq
iterate
返回一个
Cons
围绕
LazySeq
。因此在下面的类和实现测试中,我看了
iterate
输出的
rest
。我不相信
之间的差异e> 映射
和迭代
与我的问题有关。)

“当嵌入一个表达式,强制在未实现的外部惰性序列中实现惰性序列时,会发生什么情况?” 如果强制实现内部序列的表达式位于外部序列的未实现部分,则无任何内容

回答:这似乎取决于您如何创建外部惰性序列。如果外部序列来自映射,则内部序列被实现,如果外部序列用于迭代,则不是 不,这只取决于强制表达式是否在未实现部分。无论是
map
还是
iterate
都不会实现任何尚未实现的内容

“描述下面发生的情况” 你需要仔细考虑这些规则。你的例子的行为主要是渴望与懒惰评估(Clojure是渴望)的结果,并且只与懒惰序列相关

第一个示例

首先考虑表格

(def doa-twice-map (doa-twice three-vec))
第一个元素
def
表示一种特殊的形式,带有规则,但特别是当提供第二个参数时,它将被计算。特别是,您正在计算

(doa-twice three-vec)
(doall-once three-vec)
(doall (map print-times-10-ret three-vec))
此表单的评估是在
三个vec
上两次调用
doa
,如下所示(替换后)

要计算此表单,必须首先计算参数(Clojure进行急切计算)

(doa-twice three-vec)
(doall-once three-vec)
(doall (map print-times-10-ret three-vec))
您的
doall once
被参数
three-vec
调用。现在您正在计算

(doa-twice three-vec)
(doall-once three-vec)
(doall (map print-times-10-ret three-vec))
这将调用参数上的
doall
,该参数首先被计算以创建一个惰性序列。
doall
根据定义强制实现该惰性序列。在该实现过程中,您将对
三个vec
的连续元素调用
print-times-10-ret
,从而强制实现它。

因此,您在这里看到的行为是急切求值链接的结果。急切求值与懒惰求值(Clojure是急切的)不能与懒惰与非懒惰序列混淆(Clojure两者都有)

第二个示例

评估特殊
def
表单时

(def doall-once-iter (iterate doall-once three-vec))
这导致对第二个参数进行评估

(iterate doall-once three-vec)
此表单的求值将对其参数调用
iterate
。iterate创建一个
Cons
-单元格,该单元格由
3个vec
和一个惰性序列组成。作为求值结果的
Cons
-单元格是一个值,从而结束此处的急切求值链下降。此值设置为的根绑定e> doall once itervar由
def
执行。这是
def
表单评估的结束

插入语 (有一个怪癖,当map返回一个LazySeq时,iterate返回一个围绕LazySeq的Cons。因此在下面的类和实现测试中,我查看了iterate的其余输出。我不相信map和iterate之间的差异与我的问题有关。)

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


另请参阅如何在不强制实现的情况下计算序列的已实现/非惰性部分。或者,作为对我认为也是你在Clojure Google Group上提出的问题的回答。

感谢你提供了如此详细的答案。我不得不通读了几遍,以消除我知道的困惑,但现在我认为关键是p点是:我将函数
doall once
作为参数传递给
iterate
,由于
iterate
在实现部分序列之前不会调用该函数,因此没有输出。而在
doa tweep
的定义中,实际上有一个应用程序
doall once
,以及其他的功能事情就是这样发生的。(如果这一切看起来都是正确的,不需要回答。)是的,对了,这就是我在谷歌小组的位置。(顺便说一句,我确实理解了评估,但是,很明显,我对惰性序列的困惑让我失去了理智,我很高兴你了解了细节。)