Clojure 克洛朱尔扁平和懒惰

Clojure 克洛朱尔扁平和懒惰,clojure,lazy-evaluation,flatten,Clojure,Lazy Evaluation,Flatten,不确定在构造惰性序列时使用flatte时观察到的行为是什么 查看clojure.core中的源代码,我可以看到flatte函数调用filter,因此应该返回一个惰性序列——我认为。但是下面的代码片段给了我一个stackoverflow错误。在代码段中,当对扁平化的调用替换为对concat的调用时,它工作得很好 (defn l-f [c] (if (nil? c) [] (lazy-seq (flatten (cons [[ :h :j] :a :B] (l-f (rest c))

不确定在构造惰性序列时使用flatte时观察到的行为是什么

查看clojure.core中的源代码,我可以看到flatte函数调用filter,因此应该返回一个惰性序列——我认为。但是下面的代码片段给了我一个stackoverflow错误。在代码段中,当对扁平化的调用替换为对concat的调用时,它工作得很好

(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.
这是一个相当做作的例子。另外,我知道展平和concat将为我提供嵌套级别不同的序列


我试图弄明白为什么扁平化似乎打破了惰性,尽管我对clojure.core中代码的(有限的)理解表明了相反的观点。

惰性只是让你走了这么远-惰性只是意味着序列在创建时没有完全实现,但从另一个序列构建一个惰性序列有时需要向前看几个值。在这种情况下,
flatte
的实现不能很好地使用您调用它的递归方式

首先,
flatten
函数调用
tree seq
对集合的内容进行深度优先遍历。依次,
tree-seq
使用提供的序列调用
mapcat
,该序列委托给
apply
,该序列实现序列中的前几个项,以确定要调用的函数的arity。实现序列中的前几个项会导致对
l-f
的递归调用,该调用会对其余参数调用
flant
,并陷入无限循环

在这种特殊情况下,不需要递归调用
flant
,因为在第一次调用之后的任何调用都不会产生任何效果。因此,可以通过将惰性序列的生成与它的展平分离来修复函数:

(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))))