宏在定义时将键视为真
Macro treat keys as true when defined
在 elisp 中使用 cl-defmacro
s 时是否可以将键视为 true?例如,
(cl-defmacro mac (&key a b c)
`(,@(if a "a" (if b "b" "c"))))
(mac :a)
"c"
我可以在不需要给 :a
一个像 (mac :a t
的值的情况下计算 "a" 吗)。我不知道相同的语义是否适用于 common-lisp
无法使用基本语言执行此操作。可以定义一个 defun
之类的宏来执行此操作。您希望 仅 允许将这些设置为 true 还是希望提供 t
以外的值(或 nil
被省略)?第一种情况可以通过写一些宏来完成。第二种情况不能很好地完成(具体来说 (mac :a :b)
会做 a <- t; b <- t
还是 a <- :b
?)
以下是您可以为 Common Lisp 编写的内容:
(defmacro keyset-bind (keys-and-vars form &body body)
(let (syms vars
(keyv (gensym "KEY")))
(loop for key in keys-and-vars
for sym = (if (consp key)
(car key)
(intern (symbol-name key) "KEYWORD"))
for var = (if (consp key) (cadr key) key)
collect sym into symst
collect var into varst
finally (setf syms symst vars varst))
`(let ,vars
(loop for ,keyv in ,form
do (case ,keyv
,@(loop for sym in syms
for var in vars
collect `((,sym) (setf ,var t)))
(t (error "unrecognised keyword ~a" ,keyv))))
,@body)))
然后你可以像这样使用它:
(defun mac (&rest switches)
(keyset-bind (a b (:t foo)) switches
(list a b foo)))
CL-USER> (mac :a)
(T NIL NIL)
CL-USER> (mac :b :t)
(NIL NIL T)
CL-USER> (mac :baz)
;; Error ...
可以编写一个替代方案 defun
,它以这种方式接受例如 &switch
参数类型,但随后您需要决定如何使其与其他参数类型和关键字交互,并且 &allow-other-keys
和 :allow-other-keys t
。总的来说,所有这些都是一个坏主意,不鼓励与上面的任何形式的混合(甚至使用),因为它很难知道一个不熟悉的函数调用是否会被解释为普通关键字或 set-of-keywords。如果你想要一种支持这种东西的语言,请查看 perl6,其中关键字是 key-value-pair 类型并且 key => true
和 key => false
.
有特殊语法
在 elisp 中使用 cl-defmacro
s 时是否可以将键视为 true?例如,
(cl-defmacro mac (&key a b c)
`(,@(if a "a" (if b "b" "c"))))
(mac :a)
"c"
我可以在不需要给 :a
一个像 (mac :a t
的值的情况下计算 "a" 吗)。我不知道相同的语义是否适用于 common-lisp
无法使用基本语言执行此操作。可以定义一个 defun
之类的宏来执行此操作。您希望 仅 允许将这些设置为 true 还是希望提供 t
以外的值(或 nil
被省略)?第一种情况可以通过写一些宏来完成。第二种情况不能很好地完成(具体来说 (mac :a :b)
会做 a <- t; b <- t
还是 a <- :b
?)
以下是您可以为 Common Lisp 编写的内容:
(defmacro keyset-bind (keys-and-vars form &body body)
(let (syms vars
(keyv (gensym "KEY")))
(loop for key in keys-and-vars
for sym = (if (consp key)
(car key)
(intern (symbol-name key) "KEYWORD"))
for var = (if (consp key) (cadr key) key)
collect sym into symst
collect var into varst
finally (setf syms symst vars varst))
`(let ,vars
(loop for ,keyv in ,form
do (case ,keyv
,@(loop for sym in syms
for var in vars
collect `((,sym) (setf ,var t)))
(t (error "unrecognised keyword ~a" ,keyv))))
,@body)))
然后你可以像这样使用它:
(defun mac (&rest switches)
(keyset-bind (a b (:t foo)) switches
(list a b foo)))
CL-USER> (mac :a)
(T NIL NIL)
CL-USER> (mac :b :t)
(NIL NIL T)
CL-USER> (mac :baz)
;; Error ...
可以编写一个替代方案 defun
,它以这种方式接受例如 &switch
参数类型,但随后您需要决定如何使其与其他参数类型和关键字交互,并且 &allow-other-keys
和 :allow-other-keys t
。总的来说,所有这些都是一个坏主意,不鼓励与上面的任何形式的混合(甚至使用),因为它很难知道一个不熟悉的函数调用是否会被解释为普通关键字或 set-of-keywords。如果你想要一种支持这种东西的语言,请查看 perl6,其中关键字是 key-value-pair 类型并且 key => true
和 key => false
.