问:是否可以编写一个Common Lisp函数,该函数按位置或关键字接受相同的参数?如果是这样,怎么样?
例如,如何重写以下函数:
(defun fnx (&key a b c)
(list a b c))
这样,人们可以通过以下各种方式合法地称呼它:
(fnx 1 2 3)
(fnx :a 1 :b 2 :c 3)
(fnx 1 2 :c 3)
答案 0 :(得分:3)
是的,你可以,但是,不,你不想。
更准确地说,如果您可以编写规范,可以在Lisp中实现它,但我认为您不能编写明确的规范。例如,这些调用应该返回什么:
(fnx :a :b :c)
(fnx :a :c :b)
(fnx :b :a :a)
(fnx :a :a :a)
和许多其他角落案件。
当然,您可以写下这样的内容:
(defun parse-my-args (&rest args)
(let (a b c (curpos 0))
... some hairy processing
(values a b c)))
(defun fnx (&rest args)
(multiple-values-bind (a b c) (parse-my-args args)
...))
并声明无论代码做什么都是正确的,但这看起来不是一个好主意。
我建议你考虑一下你想要完成的事情并提出一个问题。
答案 1 :(得分:3)
除了sds's answer之外,我建议您阅读“this chapter”的Practical Common Lisp。
本书的作者描述了如何组合不同类型的函数参数以及应该避免哪些组合。
以下是相关引文:
其他两种组合,&可选或& rest 参数与& key 参数相结合,可能会让您感到有些惊讶行为。 < ...>您可以安全地组合& rest 和& key 参数,但最初的行为可能有点令人惊讶。通常情况下,参数列表中存在& rest 或& key 会导致所需值和& optional 参数之后的所有值保留已经填写以便以特定方式处理 - 或者收集到& rest 参数的列表中,或者根据以下内容分配给相应的& key 参数关键字。如果& rest 和& key 都出现在参数列表中,则会发生这两件事 - 所有剩余的值(包括关键字本身)都会被收集到列出与& rest 参数绑定的列表,相应的值也绑定到& key 参数。
因此,使用&rest
(你可以'索引'函数的参数)会排除使用&key
的可能性。
当然,人们可以使用像Lisp这样疯狂的工具做任何疯狂的混乱,但在这种特殊情况下它是不值得的。