Lisp 为什么应用函数会抱怨长列表?

Lisp 为什么应用函数会抱怨长列表?,lisp,common-lisp,apply,sieve-of-eratosthenes,wheel-factorization,Lisp,Common Lisp,Apply,Sieve Of Eratosthenes,Wheel Factorization,作为其中的一部分,我试图用一个因式分解轮来编写一个代码。到目前为止,我的代码是: (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 factor

作为其中的一部分,我试图用一个因式分解轮来编写一个代码。到目前为止,我的代码是:

(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允许实现限制可传递给函数的最大参数数。该限值由给出,可以小到50

对于行为类似于代数群算子的函数,遵循 关联属性(
+
列表
,以及其他),我们可以通过使用
减少
在将函数视为二进制函数的同时抽取输入列表来绕过限制

例如,要添加一个大的数字列表:
(reduce#'+list)
而不是
(apply#'+list)

关于
reduce
在Common Lisp中,即使列表为空,
reduce
也会正常工作。很少有其他语言提供这种功能,而且它实际上并非来自
reduce
:它不适用于所有函数。但是使用
+
我们可以编写
(reduce#'+nil)
并计算零,就像
(apply#'+nil)
一样

为什么呢?因为
+
函数可以用零参数调用,并且当用零参数调用时,它会生成加法组的标识元素:
0
。这与
reduce
功能相吻合

在某些其他语言中,必须为
fold
reduce
函数指定初始种子值(如
0
),否则为非空列表。如果两者都未给出,则为错误

公共Lisp
reduce
,如果给它一个空列表并且没有
:initial value
,将调用不带参数的内核函数,并使用返回值作为初始值。由于该值是唯一的值(列表为空),因此返回该值

注意对于最左边的参数有特殊规则的函数。例如:

(apply #'- '(1)) -> -1  ;; same as (- 1), unary minus semantics.

(reduce #'- '(1)) -> 1  ;; what?
reduce
给出一个单元素列表时,它只返回元素而不调用函数

基本上,它建立在上述数学假设的基础上,即如果没有提供
:初始值
,则
f
预计将支持
(f)->i
,其中
i
是与
f
相关的某个标识元素,因此
(f i x)->x
。这是在减少单例列表时使用的初始值,
(减少#'f(列表x))->(f(f)x)->(f i x)->x

-
函数不遵守这些规则
(-a0)
意味着“从
a
中减去零”,因此产生
a
,而
(-a)
a
的加反,可能纯粹是出于实用的、符号化的原因(即不让Lisp程序员编写
(-0a))
只是为了翻转一个标志,只是为了让
-
减少
应用
下的行为更加一致。
-
函数也不能用零参数调用

如果我们想从某个值
x
中减去一系列数字,其模式是:

(reduce #'- list-of-numbers :initial-value x)

错过这个算法的要点(和优点)是非常流行的。Eratosthenes的筛分基于重复添加;它不使用
mod
或任何其他方法测试可分性。(参见示例…)感谢您的链接!我的
因子分解轮
也很糟糕,所以我想我将重新开始。事实上,我通过创建一个
环列表
函数来解决这个问题,该函数将整个列表作为一个参数。不过,我可能会从头开始重做。幂等性的意思是其他的东西,即。使用
x
表示
f/[x]
源于折叠的定义(
/
),即
f/[x,…ys…]==x`f`(f/ys)
,因此
f/[x]==f/[x,…]=x`f`(f/[])==x
,因为
f/[]
应该是
f
的标识元素(例如
+
的0,而
的标识元素是1,正如你正确指出的那样。@WillNess谢谢;我修正了“幂等元”的误用;请随时回复。