我编写了一个函数is-prime
来验证给定的数字是否为素数,并相应地返回t
或nil
。
(is-prime 2) ; => T
(is-prime 3) ; => T
(is-prime 4) ; => NIL
到目前为止,这么好。现在我想在min
和max
之间生成一个素数列表,所以我想提出一个函数,它将这两个值作为参数并返回所有素数的列表:
(defun get-primes (min max)
...)
现在这是我目前陷入困境的地方。我可以做的事情当然是创建一个列表,其中包含从min
到max
的所有数字的范围,并在其上运行remove-if-not
。
无论如何,这意味着,我首先必须创建一个潜在的巨大的列表,其中包含许多我扔掉的数字。所以我想反过来这样做,建立一个列表,其中只包含根据min
谓词实际上是素数的max
和is-prime
之间的数字。
如何以功能方式执行此操作,即不使用loop
?我目前的方法(loop
)看起来像这样:
(defun get-primes (min max)
(loop
for guess from min to max
when (is-prime guess)
collect guess))
也许这是一个完全愚蠢的问题,但我想我没有看到森林里的树木。
任何提示?
答案 0 :(得分:11)
Common Lisp不支持纯 功能编程方法。该语言基于更实用的底层机器视图:没有 TCO ,堆栈是有限的,各种资源是有限的(允许的参数数量等等)。 ),变异是可能的。对于任何Haskell爱好者来说,这听起来并不是很激动人心。但Common Lisp是为编写Lisp应用程序而开发的,而不是用于推动FP研究和开发。 Common Lisp中的评估(通常在Lisp中)是 strict 而不是 lazy 。默认数据结构也不是 lazy 。虽然有 lazy 库。 Common Lisp也没有提供标准功能,如 continuations 或 coroutines - 在这种情况下可能会有用。
默认的Common Lisp方法是非功能性的,并使用某种迭代构造:DO
,LOOP
或ITERATE库。就像你的例子。 Common Lisp用户发现它非常好。有些像我一样认为迭代是有史以来发明的最好的循环结构。 ;-)优点是创建高效代码相对容易,即使宏具有大量实现。
有多种方法可以采用不同的方式:
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
生成器作为练习。 ; - )