作为一些欧拉苦难的一部分,我正试图用分解轮编码一个Eratosthenes的筛子.到目前为止我的代码是:
(defun ring (&rest content) "Returns a circular list containing the elements in content. The returned list starts with the first element of content." (setf (cdr (last content)) content)) (defun factorization-wheel (lst) "Returns a circular list containing a factorization wheel using the list of prime numbers in lst" (let ((circumference (apply #'* lst))) (loop for i from 1 to circumference unless (some #'(lambda (x) (zerop (mod i x))) lst) collect i into wheel finally (return (apply #'ring (maplist #'(lambda (x) ; Takes exception to long lists (?!) (if (cdr x) (- (cadr x) (car x)) (- circumference (car x) -1))) wheel)))))) (defun eratosthenes (n &optional (wheel (ring 4 2))) "Returns primes up to n calculated using a Sieve of Eratosthenes and a factorization wheel" (let* ((candidates (loop with s = 1 for i in wheel collect (setf s (+ i s)) until (> s n)))) (maplist #'(lambda (x) (if (> (expt (car x) 2) n) (return-from eratosthenes candidates)) (delete-if #'(lambda (y) (zerop (mod y (car x)))) (cdr x))) candidates)))
对于超过6个元素的车轮,我得到以下结果.我真的不明白为什么:
21 > (factorization-wheel '(2 3 5 7 11 13)) (16 2 4 6 2 6 4 2 4 6 6 2 6 4 2 6 4 6 8 4 ...) 21 > (factorization-wheel '(2 3 5 7 11 13 17)) > Error: Too many arguments. > While executing: FACTORIZATION-WHEEL, in process listener(1).
该算法似乎工作正常,并且使用具有6个或更少元素的轮子来制作素数.
当长名单传递给他们时,显然apply
还是ring
会嗤之以鼻.
但是,列表不应该算作单个参数吗?我承认我完全陷入困境.任何输入都表示赞赏.
ANSI Common Lisp允许实现约束可以传递给函数的最大参数数量.这个限制由call-arguments-limit给出,可以小到50.
对于行为类似代数组操作符遵循关联属性(+
,list
和其他)reduce
的函数,我们可以通过使用抽取输入列表同时将函数视为二进制来绕过限制.
例如,添加一个大的数字列表:(reduce #'+ list)
而不是(apply #'+ list)
.
reduce
在Common Lisp中,reduce
即使列表为空,也会起作用.很少有其他语言能够为您提供此功能,而且它实际上并非来自reduce
:它不适用于所有功能.但是+
我们可以写(reduce #'+ nil)
,它计算零,就像(apply #'+ nil)
.
这是为什么?因为+
可以使用零参数调用该函数,并且在使用零参数调用时,它会为添加剂组生成标识元素:0
.这与reduce
功能相吻合.
在某些其他语言中,fold
或reduce
函数必须给出初始种子值(如0
),或者非空列表.如果两者都没有,那就是错误.
Common Lisp reduce
,如果给出一个空列表而不是:initial-value
,将调用没有参数的内核函数,并使用返回值作为初始值.由于该值是唯一的值(列表为空),因此返回该值.
注意具有最左边参数的特殊规则的函数.例如:
(apply #'- '(1)) -> -1 ;; same as (- 1), unary minus semantics. (reduce #'- '(1)) -> 1 ;; what?
发生了什么,当reduce
给出一个单元素列表时,它只返回元素而不调用该函数.
基本上它建立在上面提到的数学假设之上,如果没有:initial-value
提供,那么f
预期会支持(f) -> i
,其中i
有一些与之相关的标识元素f
,以便(f i x) -> x
.这在减少单例列表时用作初始值(reduce #'f (list x)) -> (f (f) x) -> (f i x) -> x
.
该-
功能不遵守这些规则.(- a 0)
意思是"从减为零a
,因此收益率" a
,而(- a)
是反加a
,可能是纯粹务实,符号上的原因(即,不使Lisp的程序员写的(- 0 a)
只是翻转的标志,不仅仅是因为着想-
下的行为更加一致reduce
和apply
) .-
也可以不使用零参数调用该函数.
如果我们想要获取一个数字列表并从某个值中减去它们x
,那么它的模式是:
(reduce #'- list-of-numbers :initial-value x)