Common lisp 我如何定义a&;取代&;Lisp中的可选参数

Common lisp 我如何定义a&;取代&;Lisp中的可选参数,common-lisp,Common Lisp,我刚开始编写这个函数,我想知道是否有一种方法,如果只输入了&key参数,&optional列表可以被忽略 (defun test (&optional arg (i 0) &key (size s)) ...) 我希望能够跑步 (test arg) 或 而且 (test :size) 现在这是一个更好的模型,但我不知道在参数列表中放置:size (defun test (&optional arg (i 0)) (cond ((eq arg

我刚开始编写这个函数,我想知道是否有一种方法,如果只输入了&key参数,&optional列表可以被忽略

(defun test (&optional arg (i 0) &key (size s))
  ...)
我希望能够跑步

(test arg)

而且

(test :size)
现在这是一个更好的模型,但我不知道在参数列表中放置:size

    (defun test (&optional arg (i 0))
      (cond ((eq arg nil) (return-from test (test-1)))
        ((listp arg)
         (return-from test (test-2 arg)))
        ((pointerp arg) (mem-aref (test-3 arg) :int i))
            (:size (size-test arg))
        (t nil)))

    so i can run (test) and get:

    <output of (test-1)>


    I can run (test '(1 2 3)) and get:


    <output of (test-2 arg)>


    I can run (test <pointer> 0)

    and output is:

    <output of (mem-aref (test-3 arg) :int i)>

    I can run (test :size) and get:

    <output of (test-size arg)>
(除雾测试和可选参数(i 0))
(条件((等式arg nil)(测试返回(测试1)))
((listp arg)
(测试返回(测试2参数)))
((pointerp arg)(mem aref(test-3 arg):int i))
(:尺寸(尺寸测试参数))
(t零)
因此,我可以运行(测试)并获得:
我可以运行(测试’(1 2 3))并获得:
我可以运行(测试0)
输出为:
我可以运行(测试:大小)并获得:
简而言之,“否”。这是不可能实现的。作为一般规则,尽量避免混合使用
&rest
&optional
&key
参数,因为它们之间的相互作用很微妙,而且往往会让您感到困惑,而不是实际有用


此外,如果
:size
是一个关键字参数,则hen
(测试:size)
缺少一个参数(绑定
size
的值)。您最好的选择可能是查看
arg
,看看它是
:size
还是其他什么。

您必须使用
&rest
参数列表并在函数中处理它

应避免混合使用可选参数和关键字参数。使用可选参数和关键字参数是不好的风格。这是使用该函数的少数函数(如
从字符串读取
)出现无数错误的根源。

混合了可选参数和关键字参数 混合使用可选参数和关键字参数仍然不是一件容易的事情。如果函数接受可选参数,则除非还提供了可选参数,否则将无法使用关键字参数。否则,第一个关键字将被解释为可选参数,依此类推。例如,请参阅以下堆栈溢出问题:。正如这个问题的答案所指出的,混合使用可选参数和关键字参数通常是一种容易出现错误的做法。Common Lisp使用它,并且它经常导致人们陷入麻烦

不过,您所建议的不仅仅是一个同时使用关键字和可选参数的函数,而且,从听起来,实际上是对参数类型进行一些检查,在一种情况下采取一种行为,在另一种情况下采取另一种行为。在这种情况下,如果
i
应该是一个数字,那么可以检查第一个参数,如果它是一个数字,则将其视为可选参数,其余作为关键字参数,如果它不是一个数字,则将整个列表视为关键字参数。您可以使用一个
&rest
参数来实现这一点,该参数可以以不同的方式进行分解:

(defun frob (&rest args)
  (flet ((frob-driver (i size)
           (list i size)))
    (if (or (endp args) (numberp (first args)))
        ;; no args, or the first argument is a number (and thus
        ;; not a keyword argument)...
        (destructuring-bind (&optional (i 'default-i) &key (size 'default-size)) args
          (frob-driver i size))
        ;; otherwise, there are some non-numeric arguments at 
        ;; beginning, so it must be the keyword list, and that the
        ;; "optional" wasn't provided.
        (destructuring-bind (&key (size 'default-size) &aux (i 'default-i)) args
          (frob-driver i size)))))
没有关键字符号的关键字参数 在评论中,您提到您希望能够在参数列表中使用非关键字符号作为关键字。这很容易。在HyperSpec中,描述了关键字参数的语法:

[&key {var | ({var | (keyword-name var)} [init-form [supplied-p-parameter]])}* [&allow-other-keys]] 
这意味着您可以定义如下函数:

(defun frob (&key foo ((bar-keyword bar-variable) 'default-baz))
  (list foo bar-variable))

发布作为答案,因为我解决了这里的主要问题是我得出的结果代码,cond语句才是问题所在。&args的使用产生了另一个问题,该帖子正在讨论中。
((symbolp(cadr args))(%vector float size(first args)))
行是我从Joshua Taylors那里得到的,内容非常丰富,写得很好

(defun vector-float (&rest args)
  (cond ((eq (first args) nil) (return-from vector-float (%vector-float)))
    ((listp (first args))
     (c-arr-to-vector-float (first args)))
    ((symbolp (cadr args)) (%vector-float-size (first args)))
    ((pointerp (first args)) (mem-aref (%vector-float-to-c-array (first args)) :float (second args)))
    (t nil)))

谢谢你的回复:),我想知道有没有办法用符号,而不是关键字,或者无论如何?@user3517736关键字是符号。关键字符号在执行关键字参数时没有什么特别之处,只是它们是默认值。您可以使用任何符号作为关键字参数,例如to do
(foo my package::a 1 your package::b 2)
。在中,您可以看到指定关键字参数的完整语法是
[&key{var}({var}(关键字名称var)}[init form[supplied-p-parameter]]}*[&allow-other-key]]]
@Joshua Taylor.。我如何开始发明一种方法来实现这一点,这会让我的代码变得非常漂亮,感谢您加入btw:)@user3517736我已经添加了。谢谢:),这更接近了,但在&rest args列表中,我如何定义我的(I 0),它必须在那里,当然感谢您迄今为止的出色回答,但我希望在调用(test:size)运行特定函数时,不要在:size like(test:size 0)之后添加任何内容…对不起,我应该说得更清楚一些…但我想:大小是一个关键字,所以它是彩色的…到目前为止,我学到了很多though@user3517736好的,那么您可能需要对参数列表进行更复杂的检查(例如,检查其长度等)。如果您可以更新问题以显示您希望函数可调用的所有允许方式,我打赌我们可以找到一种方法。非常感谢您对这一问题的关注…我在您请求时写了一篇编辑感谢您用一些示例更新您想做的事情,但是
(test:size)
?当您提供
arg
i
时,则
:size
必须与值一起使用,例如
(test arg i:size size)
。我理解希望使用关键字参数而不提供所有可选参数,例如
(test:size)
(test arg:size size)
,但我不确定您将拥有什么
(test:size)
。实现您想要的并不那么困难,但您需要首先更具体地指定它。根据您的描述,编写此文件的更简单方法可能是只使用
(defun test(arg I&key size)…
,并附带文档:arg是列表或符号:size。如果arg是列表,则
(defun frob (&key foo ((bar-keyword bar-variable) 'default-baz))
  (list foo bar-variable))
(frob :foo 1 'bar-keyword 2)
;=> (1 2)

(frob :foo 3)
;=> (3 default-baz)

(frob 'bar-keyword 2)
;=> (nil 2)
(defun vector-float (&rest args)
  (cond ((eq (first args) nil) (return-from vector-float (%vector-float)))
    ((listp (first args))
     (c-arr-to-vector-float (first args)))
    ((symbolp (cadr args)) (%vector-float-size (first args)))
    ((pointerp (first args)) (mem-aref (%vector-float-to-c-array (first args)) :float (second args)))
    (t nil)))