为什么函数应用会抱怨长列表?
Why does function apply complain about long lists?
作为某些 Eulerian travails, I'm trying to code a Sieve of 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
,将不带参数调用内核函数,并使用return值作为初始值价值。由于该值是唯一的值(列表为空),因此该值是 returned.
注意最左边参数有特殊规则的函数。例如:
(apply #'- '(1)) -> -1 ;; same as (- 1), unary minus semantics.
(reduce #'- '(1)) -> 1 ;; what?
发生的事情是,当 reduce
被赋予一个单元素列表时,它只是 return 元素而不调用函数。
基本上它是建立在上面提到的数学假设之上的,如果没有提供 :initial-value
那么 f
应该支持 (f) -> i
,其中 i
是一些身份与 f
相关的元素,因此 (f i x) -> x
。这个作为单例列表缩减时的初始值,(reduce #'f (list x)) -> (f (f) x) -> (f i x) -> x
.
-
函数不遵守这些规则。 (- a 0)
表示 "subtract zero from a
",因此得到 a
,而 (- a)
是 a
的加法逆元,可能是出于纯粹实用的符号原因(即,不使 Lisp程序员写 (- 0 a)
只是为了翻转一个符号,只是为了让 -
在 reduce
和 apply
下表现得更一致)。 -
函数也不能用零参数调用。
如果我们想获取一个数字列表并从某个值 x
中减去所有数字,则模式为:
(reduce #'- list-of-numbers :initial-value x)
作为某些 Eulerian travails, I'm trying to code a Sieve of 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
,将不带参数调用内核函数,并使用return值作为初始值价值。由于该值是唯一的值(列表为空),因此该值是 returned.
注意最左边参数有特殊规则的函数。例如:
(apply #'- '(1)) -> -1 ;; same as (- 1), unary minus semantics.
(reduce #'- '(1)) -> 1 ;; what?
发生的事情是,当 reduce
被赋予一个单元素列表时,它只是 return 元素而不调用函数。
基本上它是建立在上面提到的数学假设之上的,如果没有提供 :initial-value
那么 f
应该支持 (f) -> i
,其中 i
是一些身份与 f
相关的元素,因此 (f i x) -> x
。这个作为单例列表缩减时的初始值,(reduce #'f (list x)) -> (f (f) x) -> (f i x) -> x
.
-
函数不遵守这些规则。 (- a 0)
表示 "subtract zero from a
",因此得到 a
,而 (- a)
是 a
的加法逆元,可能是出于纯粹实用的符号原因(即,不使 Lisp程序员写 (- 0 a)
只是为了翻转一个符号,只是为了让 -
在 reduce
和 apply
下表现得更一致)。 -
函数也不能用零参数调用。
如果我们想获取一个数字列表并从某个值 x
中减去所有数字,则模式为:
(reduce #'- list-of-numbers :initial-value x)