当前位置:  开发笔记 > 编程语言 > 正文

为什么函数适用于长列表?

如何解决《为什么函数适用于长列表?》经验,为你挑选了1个好方法。

作为一些欧拉苦难的一部分,我正试图用分解轮编码一个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会嗤之以鼻.

但是,列表不应该算作单个参数吗?我承认我完全陷入困境.任何输入都表示赞赏.



1> Kaz..:

ANSI Common Lisp允许实现约束可以传递给函数的最大参数数量.这个限制由call-arguments-limit给出,可以小到50.

对于行为类似代数组操作符遵循关联属性(+,list和其他)reduce的函数,我们可以通过使用抽取输入列表同时将函数视为二进制来绕过限制.

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

注意事项 reduce

在Common Lisp中,reduce即使列表为空,也会起作用.很少有其他语言能够为您提供此功能,而且它实际上并非来自reduce:它不适用于所有功能.但是+我们可以写(reduce #'+ nil),它计算零,就像(apply #'+ nil).

这是为什么?因为+可以使用零参数调用该函数,并且在使用零参数调用时,它会为添加剂组生成标识元素:0.这与reduce功能相吻合.

在某些其他语言中,foldreduce函数必须给出初始种子值(如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)只是翻转的标志,不仅仅是因为着想-下的行为更加一致reduceapply) .-也可以不使用零参数调用该函数.

如果我们想要获取一个数字列表并从某个值中减去它们x,那么它的模式是:

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

推荐阅读
oDavid_仔o_880
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有