【问题标题】:Clojure flatten and lazinessClojure 扁平化和懒惰
【发布时间】:2012-09-27 16:54:36
【问题描述】:

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

查看 clojure.core 中的源代码,我可以看到 flatten 函数调用了过滤器,因此应该返回一个惰性序列 - 我认为。然而下面的 sn-p 给了我一个 stackoverflow 错误。在 sn-p 中,当对 flatten 的调用替换为对 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.

这是一个相当人为的例子。我也知道 flatten 和 concat 会给我嵌套级别不同的序列。

我试图弄清楚为什么 flatten 似乎打破了懒惰,尽管我对 clojure.core 中代码的(有限)理解表明并非如此。

【问题讨论】:

    标签: clojure lazy-evaluation flatten


    【解决方案1】:

    惰性只带您到此为止 - 惰性只是意味着序列在创建时并未完全实现,但从另一个惰性序列构建一个惰性序列有时涉及向前看一些值。在这种情况下,flatten 的实现不能很好地与您调用它的递归方式配合使用。

    首先,flatten 函数调用tree-seq 对集合内容进行深度优先遍历。反过来,tree-seq 使用提供的序列调用mapcat,该序列委托给apply,后者实现序列中的前几项以确定要调用的函数的数量。实现序列中的前几项会导致对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))))
    

    【讨论】:

      猜你喜欢
      • 2010-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-07
      • 1970-01-01
      • 2012-06-02
      相关资源
      最近更新 更多