[英]Clojure lazy-seq Natural Numbers
一個流行的在線教程提供了以下示例以構建自然數:
(def infseq (map inc (iterate inc 0)))
例如, (take 5 infseq)
給出:
1 2 3 4 5
我可以看到(iterate inc 0)
功能,但是,總的來說,我不知道發生了什么。 (例如,這不是正常的函數定義。)
有人可以解釋一下嗎?
讓我們分解一下這個表達式:
(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,並添加一個 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)
和許多其他形式。
。 出於示例的目的 ,我們可以定義map
並iterate
如下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
僅適用於單個無窮序列參數。
(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
應用於(map inc <collection>)
中的每個項目,將先前的結果轉換為[1 2 3 4 ...]
(take 5 (range)) => (0 1 2 3 4)
range
帶任何參數的range
從0開始並永遠計數,與第一個示例相同。
由於所有這些集合的長度都是無限的,因此我們需要類似的東西(take 5 <collection>)
來限制打印內容的長度。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.