以下是 Python 代码,您需要使用 Clojure 实现相同的算法:
from itertools import count
from math import sqrt
def prime_gen():
primes = []
for n in count(2):
if all(n%p for p in primes if p <= sqrt(n)):
primes.append(n)
yield n
以下是 Python 代码,您需要使用 Clojure 实现相同的算法:
from itertools import count
from math import sqrt
def prime_gen():
primes = []
for n in count(2):
if all(n%p for p in primes if p <= sqrt(n)):
primes.append(n)
yield n
我尽可能地让它像Python:
(def prime-gen
(let [primes (atom [])]
(for [n (iterate inc 2)
:when (not-any? #(zero? (rem n %))
(filter #(<= % (Math/sqrt n))
@primes))]
(do (swap! primes conj n)
n))))
(take 10 prime-gen) ; => (2 3 5 7 11 13 17 19 23 29)
Clojure不将整数0视为布尔值假。我花了几分钟才弄清楚你的Python代码正在利用这一点。
这里有一些其他Clojure中的素数算法。此外,clojure.contrib.lazy-seqs
中还实现了一个素数实现。
atom
之外,它并不是完全不符合Clojure的风格。但要避免使用atom
需要进行一些扭曲。有些算法需要副作用和非函数式编程风格(特别是像原地排序、洗牌、特定数学函数等),在这些情况下切换到使用可变数据结构是可以接受的。这就是为什么Clojure提供了它们。你甚至可以深入使用本地Java数据结构来处理这些事情。 - Brian Carper这个版本比@Brian Carper的要快得多
(def prime-gen
(let [primes (atom [2N])]
(iterate
#(let [ps @primes]
(loop [n (inc %)]
(if (loop [i 0]
(let [p (nth ps i)]
(cond
(< n (* p p)) true
(zero? (mod n p)) false
:else (recur (inc i)))))
(do (swap! primes conj n) n)
(recur (inc n)))))
(first @primes))))
这是一个相当通俗易懂的Clojure算法。我尽量保持名称不变,以便您可以看到此代码的对应关系。
(def all? (partial every? identity))
(defn prime-gen []
(let [unfold
(iterate
(fn step [[primes n]]
(if (all?
(for [p primes :when (<= p (Math/sqrt n))]
(not= 0 (mod n p))))
[(conj primes n) (inc n)]
(recur [primes (inc n)])))
[[] 2])]
(map (comp peek first) (rest unfold))))
每次迭代step
最后一行从迭代中挑选出已附加的质数。
它有效:
(take 11 (prime-gen))
=> (2 3 5 7 11 13 17 19 23 29 31)
:when (<= p (Math/sqrt n)
子句(以及其Python等价物if p <= sqrt(n)
)是无用的。我们仍然会遍历所有发现的primes
,而不是在它们变得太大以至于不可能成为因子时停止。为了修复这个问题,
:when
替换为:while
;takewhile
来包装primes
,而不是在其后跟一个if
(未经测试)。lazy-primes3
。