如何在 cl-defun 中同时使用 &key 和 &rest?
How to use &key and &rest in a cl-defun togather?
我有这样的功能
(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)
您看到的行为是 CommonLisp 指定的行为(实际上我不确定您的调用 (foo 1 2 :c 6 3 4 5)
在 Common-Lisp 中是否有效,因为我认为它会将 3 和 5 视为退化 关键字 和 5
关键字缺少值)。
IOW 您通过 &rest
获得的列表包括所有关键字。因此,如果您不想要它们,则必须手动删除它们(此时您通常最好根本不使用 &key
)。
从列表 f
中删除键 c d e
的示例:
(dolist (key '(c d e))
(cl-remf f key))
(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 的建议下,我想到了这个。我不太擅长微距,可以吗?
我有这样的功能
(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)
您看到的行为是 CommonLisp 指定的行为(实际上我不确定您的调用 (foo 1 2 :c 6 3 4 5)
在 Common-Lisp 中是否有效,因为我认为它会将 3 和 5 视为退化 关键字 和 5
关键字缺少值)。
IOW 您通过 &rest
获得的列表包括所有关键字。因此,如果您不想要它们,则必须手动删除它们(此时您通常最好根本不使用 &key
)。
从列表 f
中删除键 c d e
的示例:
(dolist (key '(c d e))
(cl-remf f key))
(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 的建议下,我想到了这个。我不太擅长微距,可以吗?