【问题标题】:Implementation of lazy filter in clojureclojure中惰性过滤器的实现
【发布时间】:2013-10-01 06:47:39
【问题描述】:

在http://clojure.org/lazy 上,filter 是这样定义的:

(defn filter
  "Returns a lazy sequence of the items in coll for which
  (pred item) returns true. pred must be free of side-effects."
  [pred coll]
  (let [step (fn [p c]
                 (when-let [s (seq c)]
                   (if (p (first s))
                     (cons (first s) (filter p (rest s)))
                     (recur p (rest s)))))]
    (lazy-seq (step pred coll))))

递归调用是filter,而不是step,这很重要吗?如果是,为什么?

【问题讨论】:

    标签: clojure lazy-sequences


    【解决方案1】:

    它与此处给出的其余代码一起使用,因为它是filter,它在lazy-seq 中进行了包装。如果step 调用自己,它会一次完成所有过滤而不是懒惰。

    (已更新。) 如果 lazy-seq 被添加到 step 的主体中,step 可以调用自己并且仍然是懒惰的。这至少可以通过以下两种方式实现:

    1. 将整个主体包裹在lazy-seq 中,并将对filter 的递归调用和recur 替换为对step 的调用;注意。在这种情况下,step 函数需要命名(通过将let 替换为letfn,适当更改语法,或者在fn 形式中添加名称:(fn step ...)); lazy-seq 将最外层的调用包装到 step 将是不必要的;此外,此时您可能根本没有内部辅助函数(直接在filter 中使用这种方法);

    2. 保留filter 中的lazy-seq 并在lazy-seq 中将递归调用包装在step(现在将是step 本身)中(剩余recur 形式)不变)。

    请注意,clojure.core/filter 具有不同的实现,具有单独的逻辑处理分块序列并且没有内部辅助函数。在非分块情况下,它的运行方式与上述 1. 中描述的 step 版本类似。

    【讨论】:

    • 但是如果我用lazy-seq包裹整个身体,那么recur就不会在尾部位置
    • @tempestadept 对,你必须用另一个递归调用来替换它。 (clojure.core/filter 在非分块情况下有效地运作。)我已经编辑了答案以考虑到这一点。
    猜你喜欢
    • 1970-01-01
    • 2011-03-15
    • 1970-01-01
    • 1970-01-01
    • 2018-12-30
    • 2020-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多