clojure懒惰功能 - Clojure Koan

时间:2014-02-14 03:00:52

标签: clojure lazy-sequences

“迭代提供了一个无限的懒惰序列”

 (= (range 20) (take 20 (iterate inc 0)))

所以我的问题是为什么它从0而不是1开始?如何理解这里的懒惰?

2 个答案:

答案 0 :(得分:3)

koan要求迭代从零开始,因为range默认情况下从0开始,这使得看起来很漂亮。在编程中开始计数是0而不是1是典型的,也是有用的。但是,该公案可以写成从1开始(或任何其他数字)

(= (range 1 21) (take 20 (iterate inc 1)))

以下是如何定义迭代

user=> (source iterate)
(defn iterate
  "Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects"
  {:added "1.0"
   :static true}
  [f x] (cons x (lazy-seq (iterate f (f x)))))

所以,这是(iterate inc 0)首先看到的方式

(cons 0, (lazy-seq (iterate inc (inc 0))))

现在,当第一个访问位置1处的特殊lazy-seq元素(即,从0开始计数后的第二个位置)时,它实际上被其扩展替换。

 -- (iterate inc (inc 0)) 
 -> (iterate inc 1) 
 -> (cons 1, (lazy-seq (iterate inc (inc 1))))

所以,序列现在看起来像

-- (cons 0, (lazy-seq (iterate inc (inc 0))))
-> (cons 0, (cons 1 (lazy-seq (iterate inc (inc 1)))))

首次访问位置2的特殊lazy-seq元素时,它实际上被其扩展替换。

 -- (iterate inc (inc 1)) 
 -> (iterate inc 2) 
 -> (cons 2, (lazy-seq (iterate inc (inc 2))))

所以,序列现在看起来像

 -- (cons 0, (cons 1 (lazy-seq (iterate inc (inc 1)))))
 -> (cons 0, (cons 1, (cons 2, (lazy-seq (iterate inc (inc 2))))))

需要注意的一些后果,但通常不担心作为新用户的任何事情

  • 在访问之前不会执行身体中的任何副作用,然后只执行一次
  • 因为您可以返回未完全实现的延迟序列,请注意依赖于动态范围,例如:在with-区块内返回。
  • 如果您持有对长/无限延迟序列的引用,例如(def numbers (iterate inc 0))并意识到他们中的一大堆,他们将留在记忆中。如果这是一个问题,请避免“抱头”。

答案 1 :(得分:2)

clojure.core/iterate有两个参数:

  1. 要应用于序列中最后一个元素的fn。应用时,它应该生成序列中的下一个元素

  2. 序列的初始值

  3. (iterate inc 0)0作为序列的初始元素。

    (take 1 (iterate inc 0)) ;; (0)