Sid*_*ias 2 clojure lazy-evaluation flatten
不确定在构造延迟序列时使用flatten时我观察到的行为是什么.
查看clojure.core中的源代码,我可以看到flatten函数调用filter,因此应该返回一个惰性序列 - 我想.但是下面的代码片段给了我一个stackoverflow错误.在使用对concat的调用替换对flatten的调用的代码段中,它工作得很好
(defn l-f [c]
(if (nil? c) []
(lazy-seq (flatten (cons [[ :h :j] :a :B] (l-f (rest c)))))))
(take 10 (l-f (repeat 2))) is how I invoke it.
Run Code Online (Sandbox Code Playgroud)
这是一个相当人为的例子.我也知道flatten和concat会给我一些嵌套级别不同的序列.
我试图找出为什么flatten似乎打破了懒惰,即使我对clojure.core中的代码的(有限的)理解建议不然.
懒惰只会带你到目前为止 - 懒惰只是意味着序列在创建时并未完全实现,但是从另一个构建一个懒惰序列有时会涉及向前看几个值.在这种情况下,实现flatten与您调用它的递归方式不能很好地协作.
首先,flatten函数调用tree-seq深度优先遍历集合的内容.反过来,使用提供的序列进行tree-seq调用mapcat,该序列委托给它apply,它实现序列中的前几个项目以确定要调用的函数的arity.实现序列中的前几个项会导致递归调用l-f,调用flatten其余参数,并陷入无限循环.
在这种特殊情况下,不需要flatten递归调用,因为在第一次调用之后的任何调用都不起作用.因此,可以通过将延迟序列的生成与其展平分离来修复您的函数:
(defn l-f [c]
(letfn [(l-f-seq [x] (if-let [s (seq x)]
(lazy-seq (cons [[:h :j] :a :B] (l-f-seq (rest s))))
[]))]
(flatten (l-f-seq c))))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
930 次 |
| 最近记录: |