Clojure 这段代码中的惰性序列是如何运行的
代码如下:Clojure 这段代码中的惰性序列是如何运行的,clojure,lazy-sequences,Clojure,Lazy Sequences,代码如下: (def fib-seq (lazy-cat [0 1] (map + (rest fib-seq) fib-seq ))) 正如我所理解的,fib-seq是一个惰性序列生成器,它生成一系列斐波那契数。 通过查看(取5个fib-seq)我将得到如下fibonacci数: (01123) 但我无法理解在需要时如何生成惰性序列,因此我添加了一些副作用 (def fib-seq (lazy-cat [0 1] (map + (do (println "R") (rest fi
(def fib-seq (lazy-cat [0 1] (map + (rest fib-seq) fib-seq )))
正如我所理解的,fib-seq
是一个惰性序列生成器,它生成一系列斐波那契数。通过查看
(取5个fib-seq)
我将得到如下fibonacci数:(01123)
但我无法理解在需要时如何生成惰性序列,因此我添加了一些副作用
(def fib-seq (lazy-cat [0 1] (map +
(do (println "R") (rest fib-seq))
(do (println "B") fib-seq))))
通过添加println
,我希望只要惰性序列在需要时尝试生成新条目,它就会打印出R
和B
,但不幸的是结果是这样的
user=> (take 5 fib-seq) ; this is the first time I take 5 elements
(0 R
B
1 1 2 3)
上面的输出看起来很奇怪,因为它没有按元素打印R和B元素,但是让我们看看下一步。 首次拍摄元素后:
user=> (take 20 fib-seq)
(0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181)
我再也不会收到R
和B
,这让我感到困惑,因为它与我对惰性序列生成的理解相冲突
有人能一步一步地给我解释一下吗?顺便问一下,是否有可能使用
debug
实用程序一步一步地调试它,就像Java
和C
一样?好的,一步一步:
(defmac)
“扩展到生成延迟串联序列的代码
提供的coll的。每个coll expr在
需要。
(懒猫xs ys zs)==(concat(懒序列xs)(懒序列ys)(懒序列zs))”
{:添加了“1.0”}
[&colls]
`(concat~@(map#(list`lazy seq%)colls)))
因此,您的代码:
(def fib seq(懒猫[01](映射+
(do(打印字母“R”)(其余字母如下)
(do(println“B”)fib-seq)
扩展到:
(def fib seq(concat(lazy seq[01]))
(续)+
(do(打印字母“R”)(其余字母如下)
(do(println“B”)fib seq(()())))
concat
本身返回一个延迟序列,这意味着在遍历fib-seq
之前,不会计算concat
表单的主体fib-seq
时(当您获取第一个5
元素时),首先计算concat
表单的主体:
(concat(惰性序列[01])
(续)+
(do(打印字母“R”)(其余字母如下)
(do(println“B”)fib-seq)
concat
返回的惰性序列的前两个元素取自(lazy seq[01])
,后者又取自[01]
;在这一点之后,[01]
被耗尽,(lazy seq[01])
也被耗尽,concat
序列的下一个元素取自(lazy seq(map…)
子序列
这里对do
特殊表单进行评估,这两种表单都是如此,您可以看到R
和B
打印出来。do
的语义是计算其中的所有表单,然后返回最后一个表单的结果
所以(do(println“R”)(rest fib seq)
打印R
,然后返回(rest fib seq)
和(do(println“B”)fib seq)的结果打印B
,然后返回fib seq
(map…
返回惰性序列;当遍历到达fib-seq
的第三个元素时,计算映射
序列的第一个元素;它是fib-seq
(即0
)的第一个元素与(其余fib-seq)
的第一个元素(即fib-seq
(即1
)的第二个元素之和。在这一点上,这两个函数都已经被计算过了,所以我们不会以无限递归结束
对于下一个元素,map
的惰性阻止了无限递归的发生,神奇的事情发生了
fib-seq
(即(取20个fib-seq)
)时,它的前几个元素已经过评估,因此不会重新评估do
特殊形式,并且遍历继续进行,不会产生副作用要在从
(rest fib-seq)
和fib-seq
提取新元素时打印R
和B
,必须执行以下操作:
(def fib序列
(懒猫[01]
(地图+
(图#(do(println“R”)%)(其余为下文)
(图#(do(println“B”)%)fib seq(())))
好的,一步一步:
(defmac)
“扩展到生成延迟串联序列的代码
提供的coll的。每个coll expr在
需要。
(懒猫xs ys zs)==(concat(懒序列xs)(懒序列ys)(懒序列zs))”
{:添加了“1.0”}
[&colls]
`(concat~@(map#(list`lazy seq%)colls)))
因此,您的代码:
(def fib seq(懒猫[01](映射+
(do(打印字母“R”)(其余字母如下)
(do(println“B”)fib-seq)
扩展到:
(def fib seq(concat(lazy seq[01]))
(续)+
(do(打印字母“R”)(其余字母如下)
(do(println“B”)fib seq(()())))
concat
本身返回一个延迟序列,这意味着在遍历fib-seq
之前,不会计算concat
表单的主体fib-seq
时(当您获取第一个5
元素时),首先计算concat
表单的主体:
(concat(惰性序列[01])
(续)+
(do(打印字母“R”)(其余字母如下)
(do(println“B”)fib-seq)
<
(map + (rest [0 1 ..]) [0 1 ..] ); the '..' means it is a lazy sequence
(map + [1 ..] [0 1 ..] )
^ ^
| ----- |
|
+
1
[0 1 1 ..]
(map + (rest [0 1 1..]) [0 1 1..] )
(map + [1 1..] [0 1 1..] )
(map + [1 1..] [0 1 1..] )
^ ^
| ----- |
|
+
2
0 1 1 2 3 5 ..
1 1 2 3 5 ..