学习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)
所有这些似乎都应该起作用(或者至少应该工作,前提是前者不起作用)。为什么我得到每个案件的虚假输出?
答案 0 :(得分:1)
您最初尝试无效的原因:
您可能希望使用以下内容:
(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
答案 1 :(得分:1)
或者,您可以使用iterate:内置函数,它懒惰地获取函数的输出并将其再次应用于函数
clojure.core/iterate
([f x])
Returns a lazy sequence of x, (f x), (f (f x)) etc.
f must be free of side-effects
为了让它工作,next-prime函数应该将其结果连接到它的输入,并返回连接。
然后你可以调用(取100(iterate list-primes [1]))来得到前100个列表 素数。
答案 2 :(得分:1)
使用next-prime
函数,您可以使用以下代码片段生成所有素数的延迟序列:
(def primes (map peek (iterate #(conj % (next-prime %)) [2])))
答案 3 :(得分:0)
您要找的组合是concat
+ lazy-seq
+本地fn。
在Clojure Contrib图书馆中查看Erathostenes'Sieve的实施: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中解决这个算法。