12

我正在努力通過Stuart Halloway的書Programming Clojure。這整個功能的東西對我來說是非常新的。Clojure函數(nth [coll索引])和作文(last(take index coll))有什麼區別

我明白

(defn fibo[] 
    (map first (iterate (fn [[a b]] [b (+ a b)]) [0 1]))) 

如何懶洋洋地產生斐波那契序列。我不明白爲什麼

(last (take 1000000 (fibo))) 

作品,而

(nth (fibo) 1000000) 

拋出一個OutOfMemoryError。有人可以解釋這兩個表達式有何不同? (第nth)以某種方式保持序列的頭部?

謝謝!

+1

這兩種方法都不適用於tryclj。因爲數字太大會導致溢出。 AFAICT你沒有提及任何事情,所以我不相信任何事情都是「持有頭腦」。你確定這不僅僅是因爲這個數字如此之大 - – 2011-12-15 15:57:14

+0

last的實現是一個簡單的O(n)尾遞歸實現,它不支持任何東西。 nth是用Java實現的,我很確定它不能保持任何東西。因此,你的兩個序列應該工作得很好(理論上)。 我能想到的唯一的東西,雖然我不清楚這會影響結果,但是你的第n個電話實際上計算的是比上次電話多1個電話。第1000000 = 1000001項(0索引) – vedang 2011-12-15 16:42:05

回答

4

我想你是在談論在google group和Rich Hickey提供的patch中討論的問題,它解決了這個問題。而後來出版的這本書沒有涉及這個話題。

clojure 1.3您的nth示例在fibo函數中稍作改進。現在,由於1.3的變化,我們應該明確地標記M以使用任意精度,或者與throwIntOverflow一致。

(defn fibo[] 
    (map first (iterate (fn [[a b]] [b (+ a b)]) [0M 1M]))) 

而且這些變化

(nth (fibo) 1000000) 

成功(如果你有足夠的內存)

1

你正在使用什麼Clojure版本?在repl上嘗試(clojure-version)。對於1.3.0中的兩個表達式我都得到了相同的結果,即整數溢出。

對於

(defn fibo[] 
    (map first (iterate (fn [[a b]] [b (+ a b)]) [(bigint 0) 1]))) 

我得到兩個表達式正確的結果(一個非常大的整數...)。

0

我認爲你可能會打你的機器特​​定的內存限制,而不是一個真正的區別功能。

看看https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java中nth的源代碼,它看起來不像是第n個或是保留頭部。

但是,第n個使用從零開始的索引,而不是按項目編號計數。您的代碼使用nth選擇序列的第1000001st個元素(索引1000000處的元素)。你用take代碼返回1000000元素序列中的最後一個元素。這是索引999999的項目。假設fib快速增長,最後一項可能是打破駱駝背部的項目。

此外,我正在檢查1.3.0源。也許早期的版本有不同的實現。爲了讓你的fibo能夠在1.3.0中正常工作,你需要使用算術函數來將數字提升爲bignums:

(defn fibo[] 
    (map first (iterate (fn [[a b]] [b (+' a b)]) [0 1]))) 
相關問題