2

我可以在 LISP 中使用关键字参数

(member 'a '(a b c) :test #'eq)

但是,当我尝试使用 apply 来调用成员方法时

(apply #'member 'a '(a b c) :test #'eq)

我有如下错误消息:

MEMBER: keyword arguments in (:TEST) should occur pairwise
 [Condition of type SYSTEM::SIMPLE-PROGRAM-ERROR]

解决方案是

(apply #'member 'a '(a b c) '(:test eq))

而没有关键字参数

(apply #'member 'a '((a b c)))

这背后的逻辑是什么?为什么 '(:test #'eq) 会引发错误?

添加

这就是我问这个问题的原因。我有来自 ANSI Common Lispbook 第 103 页的代码。

(defun our-adjoin (obj lst &rest args)
       (if (apply #'member obj lst args)
           lst
           (cons obj lst)))

当我尝试(our-adjoin 'a '(a b c))它返回结果(A B C)时,但 our-adjoin 不能翻译为(apply #'member 'a '(a b c)),因为它会引发错误(如Apply 和 lisp 中的关键字参数中所要求的那样)。

我能想到的是,&rest args给出的值是为了(apply #member 'a '(a b c) '())不引发错误。

4

2 回答 2

5

apply期望它的最后一个参数是一个列表。那是,

(apply #'foo (list 1 2 3)) == (foo 1 2 3)
(apply #'member 'a '(a b c) :test #'eq) == ??? ; is an error - #'eq isn't a list

我不知道apply#'eq函数)在哪里需要一个列表,但这就是问题所在。

您可能正在寻找funcall而不是apply

(funcall #'foo 1 2 3) == (foo 1 2 3)
(funcall #'member 'a '(a b c) :test #'eq) == (member 'a '(a b c) :test #'eq)

编辑:(apply #'member 'a '(a b c))

这与

(member 'a 'a 'b 'c)

这当然是胡说八道。将apply其视为“扩展”它的最后一个论点。

编辑2:our-adjoin代码

(our-adjoin 'a '(a b c) :test #'eq)
;; is equivalent to
(if (apply #'member 'a '(a b c) (list :test #'eq))
    lst
  (cons obj lst))
;; is equivalent to
(if (member 'a '(a b c) :test #'eq) ...)

(our-adjoin 'a '(a b c))
;; is equivalent to
(if (apply #'member 'a '(a b c) (list)) ...) ; (list) == nil
;; is equivalent to
(if (member 'a '(a b c)) ...)

因此,您的假设(等效项是(apply #'member 'a '(a b c) '()))是正确的。nil(仅供参考,'nil, (), '(), 和之间没有区别(list)。)

于 2013-04-29T01:30:58.100 回答
4

提供了APPLY以便我们可以使用计算的参数列表调用函数。

APPLY具有以下语法:

apply function &rest args+ => result*
  • 第一个参数是一个函数

  • 然后是几个参数,至少一个,其中最后一个参数需要是一个列表

于 2013-04-29T07:50:26.590 回答