一个流行的在线教程给出了这个例子来构建自然数字:
(def infseq (map inc (iterate inc 0)))
例如,(take 5 infseq)
给出:
1 2 3 4 5
我可以看到(iterate inc 0)
的作用,但是,作为一个整体,我不明白究竟发生了什么。 (例如,这不是正常的函数定义。)
有人可以解释一下吗?
答案 0 :(得分:2)
让我们打破这个表达:
(map inc (iterate inc 0)))
是具有此结构的列表(数据结构):
(function-to-call function-passed-as-first-srgument another-list-as-second-arg)
现在让我们从内到外检查它! 内心清单:
(iterate inc 0)
有这个结构
(function-to-call function-passed-as-first-argument number)
iterate
,它通过跟踪它的内部状态来创建无限序列,并且每次需要一个新值来使序列变长时,它会将函数作为第一个传递参数并在当前状态下调用它。 inc
,其中包含numbr和ads one iterate
的第三个参数是初始状态。它应该从哪里开始。因此,当评估此内部表达式时,它将立即返回表示列表的数据结构,而不实际构建该列表。当从该列表中读取第一个值时,它将返回初始值0
,当要求第二个值时,它将使用inc
函数来提供数字1
。如果再次需要第一个或第二个值,它们将按原样使用,而不是重新计算。
所以第一个参数代表一个产生所需数量的合约。这是原始表达式的第三个参数。
初始表达式采用该惰性列表并生成一个新的惰性列表。
这个新的惰性列表由map
函数返回。
(map inc (0 1 2 3 4 ... as many as you read ...))
将inc
应用于每个这些,就像它的读取一样,并且只在它被读取的那一刻(实际上它将前面的20个左右的项目缓存得更快一点)导致这个序列:
((inc 0) (inc 1) (inc 2) (inc 3) ... as much as you read from the sequence ...)
其中包括:
(1 2 3 4 ... created lazily)
与这些等效表达式的结果相同,
(rest (range))
(iterate inc 1)
以及许多其他形式。
答案 1 :(得分:2)
。 出于示例的目的,我们可以按如下方式定义map
和iterate
:
(defn iterate [f init]
(lazy-cons init (iterate f (f init))))
(defn map [f [x & xs]]
(lazy-cons (f x) (map f xs)))
...其中lazy-cons
是cons
的版本,在必须执行之前不会采取行动。它曾经是clojure.core
的一部分,因此可能已定义:
(defmacro lazy-cons [x xs]
`(lazy-seq (cons ~x ~xs)))
要理解这些定义,您需要掌握递归,懒惰,解构和宏:完成任务!但是这样做,你真的 了解clojure的序列库,包括iterate
和map
是如何工作的。这是我学习的方式。
iterate
的定义有效。 map
中的一个仅适用于单个无限序列参数。
答案 2 :(得分:1)
(take 5 (iterate inc 0)) => (0 1 2 3 4)
iterate
在循环中重复应用inc函数。你从0
开始,所以得到[0 1 2 3 ...]
(take 5 (map inc (iterate inc 0))) => (1 2 3 4 5)
(map inc <collection>)
一次对集合中的每个项目应用inc
,将之前的结果转换为[1 2 3 4 ...]
(take 5 (range)) => (0 1 2 3 4)
range
没有任何args从0开始并永远计数,与第一个例子相同。
由于所有这些集合的长度都是无限的,我们需要(take 5 <collection>)
之类的东西来限制打印的内容。