没有 apply 的普通 lisp 调用函数会导致奇数个关键字

common lisp invoking function without apply leads to odd number of keywords

我目前正在学习普通的口齿不清,偶然发现了一个我不会的问题 回答我自己:

(defun find-all (item seq &rest keyword-args &key (test #'eql)
                     test-not &allow-other-keys)
 (if test-not
   (apply #'remove item seq
          :test-not (complement test-not) keyword-args)
   (apply #'remove item seq
          :test (complement test) keyword-args)))

函数用于查找seq匹配项中的每一个元素 到测试功能。 可悲的是,我不明白为什么这里使用函数 'apply' 。 不应该只调用删除而不应用吗? 警告说:"The function has an odd number of arguments in the keyword portion" 如果我调用删除而不应用。

希望你能帮助我, 提前致谢!

我们以REMOVE的签名为例:

remove item sequence &key from-end test test-not start end count key 
=> result-sequence

以上意味着该函数接受 2 个强制参数,itemsequence,以及应使用 :key value 语法给出的其他关键字参数。如果您只提供键或值,例如:

(remove x list :count)

那就无效了。一个简单的测试是查看 关键字位置 中的参数数量,并检查给定参数的数量是否为偶数。奇怪的时候,你就知道出了问题。

如果您致电:

(remove item seq args)

你也是这种情况。 args 是您特定情况下的列表并不重要。

申请

APPLY 是一种更通用的函数调用方式:它的最后一个参数是一个 附加参数列表 .

假设args绑定到(3 4),那么:

(apply #'+ 1 args)

相当于:

(+ 1 3 4)

这也适用于关键字参数;如果 args 是列表 (:count 1),则:

(apply #'remove item seq args)

相当于:

(remove item seq :count 1)

而这里,关键字位置的参数个数是偶数。

删除并查找所有

REMOVE 接受一堆关键字参数:from-end、test、test-not、start、end、count 和 key。

现在在函数 FIND-ALL 中你只想修改一个:testtest-not 然后调用REMOVE.

FIND-ALL的参数列表怎么写

现在FIND-ALL的参数列表基本上有3个选项,因为它和REMOVE基本一样,只改变了一个参数。

  1. 列出每个关键字参数及其默认值,然后将它们传递给 REMOVE

  2. 仅列出一个其余参数列表,操作此参数列表并通过APPLY将新参数列表传递给REMOVE

  3. 1. 和 2. 的混合,如上例所示。仅列出必需的参数和要修改的关键字参数以及调用时提供的其他关键字参数的其余列表。通过 APPLY.

  4. 调用 REMOVE

三种可能性有多好?

现在 1. 的优点是您可以看到 FIND-ALL 的完整参数列表,并且它不需要 cons 参数列表。 Lisp 可以检查其中的一些。但是您确实需要复制参数列表中的所有参数以及稍后对 REMOVE 的调用。可能但不是那么好。

Then 2. 的缺点是 FIND-ALL 没有可见的参数列表,但使用一些函数来操作参数列表可能更容易编写。 3. 比较好写,就是缺少完整的参数列表。

你的例子

因此在您的示例中,它是上面的版本 3:

  • 需要的参数先传入
  • 接下来是修改后的参数
  • last 是所有关键字参数的列表

如果要将现有参数列表作为参数的一部分传递给函数,则需要 APPLY。这就是为什么在那里使用它的原因。 APPLY 使用从列表中获取的参数调用函数。

CL-USER 1 > (apply #'+ 1 2 '(3 4 5))
15

CL-USER 2 > (let ((numbers '(3 4 5)))
              (apply #'+ 1 2 numbers))
15


CL-USER 3 > (+ 1 2 3 4 5)
15