Common Lisp - 给出 &rest 列表作为参数
Common Lisp - Giving &rest Lists as Arguments
由于对一个运动问题的思考,我正在尝试编写一个函数,它接受一个输入数字和一个任意长度的除数列表来测试,以及作为布尔值的预期整除率(即余数 0) , 如果满足所有期望则返回 true(如果未指定则默认为 true)。
示例输入:
(divisible-by 10 (5 t) (4 f) 2) => t
我的阅读导致了为函数创建输入的尝试:
(defun divisible-by (numerator &rest args (&key divisors (divisorp t)))
(loop...))
我对这种输入类型的简单测试用例以各种方式出错,我通过 Google 和直接在 Stack Overflow 上搜索都没有取得成果,这让我相信我的理解不足以生成正确的关键字。
如能提供有关如何实现此类功能、我的尝试失败或无法实现此类功能的原因的指示,我将不胜感激。
除了 &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 将被忽略。
我没有看到混合 &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)
将是使用参数 t
调用的函数 5
,但 5
不是函数,因此您得到错误与 lambda 列表无关。
Defun
采用 普通 lambda 列表。那里没有解构。
&Rest
只取一个符号,在所有必选参数和可选参数填满后绑定到参数的rest。如果要解构它,请在函数体内使用 destructuring-bind
。
有时可能值得使用一个宏来预处理函数调用形式。
由于对一个运动问题的思考,我正在尝试编写一个函数,它接受一个输入数字和一个任意长度的除数列表来测试,以及作为布尔值的预期整除率(即余数 0) , 如果满足所有期望则返回 true(如果未指定则默认为 true)。
示例输入:
(divisible-by 10 (5 t) (4 f) 2) => t
我的阅读导致了为函数创建输入的尝试:
(defun divisible-by (numerator &rest args (&key divisors (divisorp t)))
(loop...))
我对这种输入类型的简单测试用例以各种方式出错,我通过 Google 和直接在 Stack Overflow 上搜索都没有取得成果,这让我相信我的理解不足以生成正确的关键字。
如能提供有关如何实现此类功能、我的尝试失败或无法实现此类功能的原因的指示,我将不胜感激。
除了 &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 将被忽略。
我没有看到混合 &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)
将是使用参数 t
调用的函数 5
,但 5
不是函数,因此您得到错误与 lambda 列表无关。
Defun
采用 普通 lambda 列表。那里没有解构。
&Rest
只取一个符号,在所有必选参数和可选参数填满后绑定到参数的rest。如果要解构它,请在函数体内使用 destructuring-bind
。
有时可能值得使用一个宏来预处理函数调用形式。