Functional programming 取决于先前元素的延迟序列

Functional programming 取决于先前元素的延迟序列,functional-programming,clojure,Functional Programming,Clojure,学习clojure,尝试创建所有素数的惰性无限序列。 我知道有更有效的算法;我做以下工作更多的是作为一个POC/课程,而不是作为一个理想的解决方案 我有一个函数,给定一系列素数,它告诉我下一个素数是什么: (next-prime [2 3 5]) ; result: 7 因此,我的惰性序列必须将自身传递给该函数,然后获取结果并将其添加到自身 我的第一次尝试: (def lazy-primes (lazy-cat [2 3 5] (find-next-prime lazy-primes)))

学习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)

所有这些似乎都应该起作用(或者至少应该起作用,因为前面的方法不起作用)。为什么我会得到每个案例的假输出?

您要寻找的组合是
concat
+
lazy seq
+local fn

请看一下在Clojure Contrib库中实现Erathostenes'Sieve:

不过,还有一句话:这个实现使用了一个更简单的方法


Clojure的另一个实现可以在中找到。但是,我不喜欢那个,因为它使用原子,而在Clojure中解决这个算法不需要原子。

您最初的尝试不起作用的原因:

  • (查找下一个prime lazy primes)返回一个整数,但lazy cat需要一个序列
  • [(find next prime lazy primes)]创建一个向量(因此是可排序的),但在第一次访问它时只对它求值一次
  • conj正在向序列的开头添加新的素数(因为lazy cat和lazy primes返回序列)。。。这可能不是你想要的!根据下一个prime的实现方式,查找下一个prime可能会让人感到困惑,而且在分块序列周围也可能存在一些微妙的问题
  • 相反,您可能希望使用以下内容:

    (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)))
    
    有点复杂,但基本上我所做的是使用高阶helper函数在一组参数上提供闭包,这些参数包括到目前为止创建的素数,以便它可以在每一步递增地生成下一个素数


    p、 我相信你们都知道,有更快的算法来生成素数!我假设这主要是为了练习Clojure和使用惰性序列,在这种情况下一切都很好!但是如果你真的关心生成大量的素数,我建议你看看

    或者,你可以使用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
    
    为了让它工作,下一个素数函数应该将其结果连接到其输入,并返回连接

    然后您只需调用(take100(iterate list primes[1])就可以得到前100个元素的列表
    素数。

    使用
    下一个素数
    函数,您可以使用以下代码片段生成所有素数的惰性序列:

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

    有趣的网站,但你能给我解释一下我的代码在做什么吗?