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
),否则为非空列表。如果两者都未给出,则为错误
公共Lispreduce
,如果给它一个空列表并且没有: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谢谢;我修正了“幂等元”的误用;请随时回复。