2011-02-10 48 views
4

學習clojure,嘗試創建所有素數的懶惰無限序列。 我知道有更高效的算法;作爲POC /課程,我比以下更理想的解決方案。依賴於前面元素的惰性序列

我有一個函數,給定的素數的序列,告訴我下一任是什麼:所以

(next-prime [2 3 5]) ; result: 7 

我的懶惰序列本身必須通過這個功能,然後拿結果,並添加到本身。

我第一次嘗試:

(def lazy-primes 
    (lazy-cat [2 3 5] (find-next-prime lazy-primes))) 

..這導致了一個IllegalArgumentException:不知道如何從創建ISEQ:java.lang.Integer中

我的第二次嘗試:

(def lazy-primes 
    (lazy-cat [2 3 5] [(find-next-prime lazy-primes)])) 

..當我詢問10個元素時,它給了我[2 3 5 7]。

嘗試3:

(def lazy-primes 
    (lazy-cat [2 3 5] 
    (conj lazy-primes (find-next-prime lazy-primes)))) 

(take 10 lazy-primes) ; result: (2 3 5 7 2 3 5 7 2 3) 

的這些似乎都像他們應該工作(或者至少應該工作鑑於前面沒有工作)。爲什麼我會得到每個案件的虛假輸出?

回答

1

原因您最初的嘗試不起作用:

  1. (發現-下一貸懶惰素數)返回一個整數,但懶惰的貓需要一個序列
  2. [(發現-下一貸lazy-primes)]創建一個向量(因此可以被seqable),但它只在第一次訪問時被評估一次
  3. conj正在向序列的開頭添加新的素數(因爲lazy-cat和lazy-primes返回一個序列)......這可能不是你想要的!它也可能是混亂的發現,未來貸取決於如何被實現,有可能是一些細微的問題,各地分塊序列以及.....

你可能反而要使用這樣的:

(defn seq-fn [builder-fn num ss] 
    (cons 
    (builder-fn (take num ss)) 
    (lazy-seq (seq-fn builder-fn (inc num) ss)))) 

(def lazy-primes 
    (lazy-cat [2 3 5] (seq-fn next-prime 3 lazy-primes))) 

有點複雜,但基本上我在做什麼是使用高階輔助函數提供了一組參數,其中包括創建至今素數的關閉,以便它可以生成在每一步增加下一個素數。

p.s.因爲我相信你知道有更快的算法來產生素數!我假設這主要是作爲Clojure的練習和使用惰性序列,在這種情況下一切順利!但如果你真的關心產生大量的素數,我建議看看Sieve of Atkin

0

您正在尋找的組合是concat + lazy-seq + local fn。

看看Erathostenes'篩在Clojure中的Contrib庫的實現:https://github.com/richhickey/clojure-contrib/blob/78ee9b3e64c5ac6082fb223fc79292175e8e4f0c/src/main/clojure/clojure/contrib/lazy_seqs.clj#L66

多說一個單詞,雖然:此實現採用了更加sophisticated algorithm for the Sieve in a functional language

Clojure的另一個實現可以在Rosetta code中找到。然而,我不喜歡那個,因爲它使用原子,你不需要在Clojure中解決這個算法。

+0

有趣的網站,但你可以給我什麼我的代碼是做一個解釋? – Kricket 2011-02-10 10:41:29

1

或者,你可以使用迭代:內置函數,懶惰地接受函數的輸出並將其應用於函數再次

clojure.core/iterate                                       
([f x])                                         
Returns a lazy sequence of x, (f x), (f (f x)) etc. 
f must be free of side-effects 

爲了讓你做它的工作,下一個主要功能應串聯其結果它的輸入,並返回串聯。

然後你可以調用(取100(iterate list-primes [1]))來獲得前100個素數的列表。

1

與您next-prime功能,您可以生成所有素數與下面的代碼片段一個懶惰的序列:

(def primes (map peek (iterate #(conj % (next-prime %)) [2])))