不使用中间列表过滤范围

时间:2016-01-17 16:02:30

标签: functional-programming lisp common-lisp primes

我编写了一个函数is-prime来验证给定的数字是否为素数,并相应地返回tnil

(is-prime 2) ; => T
(is-prime 3) ; => T
(is-prime 4) ; => NIL

到目前为止,这么好。现在我想在minmax之间生成一个素数列表,所以我想提出一个函数,它将这两个值作为参数并返回所有素数的列表:

(defun get-primes (min max)
  ...)

现在这是我目前陷入困境的地方。我可以做的事情当然是创建一个列表,其中包含从minmax的所有数字的范围,并在其上运行remove-if-not

无论如何,这意味着,我首先必须创建一个潜在的巨大的列表,其中包含许多我扔掉的数字。所以我想反过来这样做,建立一个列表,其中只包含根据min谓词实际上是素数的maxis-prime之间的数字。

如何以功能方式执行此操作,即不使用loop?我目前的方法(loop)看起来像这样:

(defun get-primes (min max)
  (loop
    for guess from min to max
    when (is-prime guess)
    collect guess))

也许这是一个完全愚蠢的问题,但我想我没有看到森林里的树木。

任何提示?

1 个答案:

答案 0 :(得分:11)

Common Lisp不支持 功能编程方法。该语言基于更实用的底层机器视图:没有 TCO 堆栈是有限的,各种资源是有限的(允许的参数数量等等)。 ),变异是可能的。对于任何Haskell爱好者来说,这听起来并不是很激动人心。但Common Lisp是为编写Lisp应用程序而开发的,而不是用于推动FP研究和开发。 Common Lisp中的评估(通常在Lisp中)是 strict 而不是 lazy 。默认数据结构也不是 lazy 。虽然有 lazy 库。 Common Lisp也没有提供标准功能,如 continuations coroutines - 在这种情况下可能会有用。

默认的Common Lisp方法是非功能性的,并使用某种迭代构造:DOLOOPITERATE库。就像你的例子。 Common Lisp用户发现它非常好。有些像我一样认为迭代是有史以来发明的最好的循环结构。 ;-)优点是创建高效代码相对容易,即使宏具有大量实现。

有多种方法可以采用不同的方式:

  • 懒惰的溪流。阅读SICP有帮助,请参阅streams上的部分。也可以在Common Lisp中轻松完成。请注意,Common Lisp对I / O流使用单词stream - 这是不同的。
  • 使用生成器功能 next-prime。从初始范围生成此函数并调用它直到您获得所有您感兴趣的素数。

以下是生成器函数的一个简单示例,从某个起始值生成偶数:

(defun make-next-even-fn (start)
  (let ((current (- start
                    (if (evenp start) 2 1))))
    (lambda ()
      (incf current 2))))


CL-USER 14 > (let ((next-even-fn (make-next-even-fn 13))) 
               (flet ((get-next-even ()
                        (funcall next-even-fn)))
                 (print (get-next-even))
                 (print (get-next-even))
                 (print (get-next-even))
                 (print (get-next-even))
                 (list (get-next-even)
                       (get-next-even)
                       (get-next-even))))

14 
16 
18 
20 
(22 24 26)

定义next-prime生成器作为练习。 ; - )

  • 使用某种更复杂的懒惰数据结构。对于Common Lisp,有 Series ,这是一个早期的迭代提议 - 也发表在CLtL2:Series。 Edi Weitz的新书Common Lisp Recipes(汉堡数学教授)有一个计算素数的系列例子。见第7.15章。您可以下载该书的源代码并在那里找到示例。
  • 系列的更简单变体,例如pipes