Common Lisp - 给予和休息列表作为参数

时间:2015-05-15 15:38:26

标签: arguments lisp common-lisp sbcl

由于围绕一个运动问题进行思考,我试图编写一个函数,该函数将输入数和任意长度的除数列表进行测试,并将预期的可分性(即余数0)作为布尔值,返回如果满足所有期望,则为true(如果未指定则默认为true)。

示例输入:

 (divisible-by 10 (5 t) (4 f) 2) => t

我的阅读导致了为该功能创建输入的尝试:

(defun divisible-by (numerator &rest args (&key divisors (divisorp t)))
  (loop...))

我对这种输入类型的简单测试用例以各种方式出错,而我在谷歌搜索和直接在Stack Overflow上搜索并没有证明是富有成效的,这使我相信我的理解不足以生成正确的关键字。

关于如何实现这样一个功能的指针,我的尝试失败或为什么这样的功能无法实现,我将非常感激地收到。

3 个答案:

答案 0 :(得分:1)

&rest之外,您不需要任何其他内容:

(defun divisible-p (number &rest divisors)
  "Check whether number is divisible by divisors."
  (dolist (spec divisors t) ; For each 'divisor' in divisors
    (etypecase spec
      ;; If divisor is a list, test if modulus of first value is 0
      ;; then compare to second (boolean)
      (cons (unless (eq (zerop (mod number (first spec)))
                        (second spec))
              (return nil)))
      ;; If divisor is an integer, return t if modulus == 0
      (integer (unless (zerop (mod number spec))
                 (return nil))))))

(divisible-p 10 '(5 t) '(4 nil) 2)
==> T
(divisible-p 10 '(5 t) '(4 nil) 2 3)
==> NIL

请注意,您需要引用列表参数,否则您将收到没有函数5的错误。

我不确定你使用&key想要完成什么,但是它们不能在CL中重复,即如果你写的话

(defun foo (&key a) (print a))
(foo :a 1 :a 2 :a 3)

仅打印3,1& 2将被忽略。

答案 1 :(得分:1)

我没有看到混合&rest&key来解决此问题的有效方法。以下是仅使用&key的示例:

 (defun divisible-by (numerator &key divisors not-divisors)
   (flet ((dividesp (denom) (= 0 (mod numerator denom))))
     (and (every #'dividesp divisors)
          (notany #'dividesp not-divisors))))

 ;; Call like:
 (divisible-by 10 :divisors (list 2 5) :not-divisors (list 4 6))
 => t

你的lambda列表有一个语法错误,与你所写的内容很接近,但有效会看起来像这样调用:

 (defun divisible-by (numerator &rest args &key divisors (divisorp t))
   (print args)
   (print divisors)
   (print divisorp))

;; Calling would look like this
(divisible-by 10 :divisors (list 11 2) :divisorp nil)

-> (:DIVISORS (11 2) :DIVISORP NIL) 
-> (11 2) 
-> NIL 

对于某项功能,您无法完全获得所需的输入。函数调用不会改变其参数的语法:(5 t)将是使用参数5调用的函数t,但5不是函数,所以你得到无论lambda列表如何都是错误。

答案 2 :(得分:0)

Defun采用普通 lambda列表。那里没有解构。

&Rest只接受一个符号,在填充所有必需参数和可选参数后,该符号与参数的 rest 绑定。如果要对其进行解构,请在函数体内使用destructuring-bind

有时使用一个带有解构 lambda列表的宏来预处理调用表单的函数可能是值得的。