0

“迭代提供了无限的惰性序列”

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

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

4

2 回答 2

3

公案要求迭代从零开始,因为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(即从我们从 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 的特殊惰性序列元素第一次被访问时,它实际上被它的扩展替换。

 -- (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))并实现它们中的一堆,它们将保留在内存中。如果这是一个问题,请避免“抱头”。
于 2014-02-14T05:01:16.613 回答
2

clojure.core/iterate有两个参数:

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

  2. 序列的初始值

(iterate inc 0)具有0作为序列的初始元素。

(take 1 (iterate inc 0)) ;; (0)
于 2014-02-14T03:06:13.867 回答