在clojure中实现惰性过滤器

时间:2013-10-01 06:47:40

标签: clojure lazy-sequences

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是否重要?如果是,为什么?

1 个答案:

答案 0 :(得分:1)

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

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

  1. 将整个正文包裹在lazy-seq中,并通过调用filter替换递归调用recurstep; NB。在这种情况下,需要命名step函数(通过将let替换为letfn,使用适当的语法更改,或者为{{1}添加名称} form:fn);然后将(fn step ...)包裹最外面的lazy-seq调用是不必要的;此外,你可能根本就没有内部帮助函数(直接在step中使用这种方法);

  2. filter保留在lazy-seq中,并将filter中的递归调用(现在将step本身包含在{{1}中)包装(step形式保持不变)。

  3. 请注意,lazy-seq具有不同的实现,具有单独的逻辑处理分块序列而没有内部辅助函数。在非分块的情况下,它的操作类似于上面1.中描述的recur版本。