我有这样的功能
(cl-defun foo (a b c d e &rest f)
nil)
参数c
,d
和e
是nil
80%的时间。
为了让它看起来更好,我这样做:
(cl-defun foo (a b &rest f &key c d e &allow-other-keys)
nil)
如果未提供c
,d
和e
,则可以。
但是,如果使用其中一个,f
会得到错误的参数。
例如:
(foo 1 2 :c 6 3 4 5)
;; ==> expected: a=1, b=2, c=6, f= (3 4 5)
;; ==> real case: a=1, b=2, c=6, f= (:c 6 3 4 5)
答案 0 :(得分:1)
您看到的行为是CommonLisp指定的行为(实际上我不确定您的调用(foo 1 2 :c 6 3 4 5)
在Common-Lisp中是否有效,因为我认为它会将3和5视为退化关键字且5
关键字缺少值。)
Iow您通过&rest
获得的列表包含所有关键字。因此,如果您不想要它们,则必须手动放下它们(此时您最好不要使用&key
)。
答案 1 :(得分:1)
(cl-defmacro foo2 (a b &rest f &key c d e &allow-other-keys)
(let (key rest)
(dolist (elt f)
(if (memq elt '(:c :d :e))
(setq key elt)
(if key
(progn
(set (intern-soft (string-remove-prefix ":" (symbol-name key))) elt)
(setq key nil))
(push elt rest))))
(setq rest (nreverse rest))
`(foo ,a ,b ,c ,d ,e ,@rest)))
(pp-macroexpand-expression '(foo2 1 2 :c 3 :d 4 :e 5 6 7 8 9))
;; ==> (foo 1 2 3 4 5 6 7 8 9)
(pp-macroexpand-expression '(foo2 1 2 3 4 5 6))
;; ==> (foo 1 2 nil nil nil 3 4 5 6)
(pp-macroexpand-expression '(foo2 1 2 3 4 5 6 :c 7 :d 8 :e 9))
;; ==> (foo 1 2 7 8 9 3 4 5 6)
(pp-macroexpand-expression '(foo2 1 2 3 :c 4 5 :d 6 7 :e 8 9))
;; Extreme case
;; ==> (foo 1 2 4 6 8 3 5 7 9)
根据@ Stefan的建议,我想出了这个。我不是很擅长宏,它有用吗?