Common lisp 回指宏符号的前缀来自另一个包,如何去掉它?
我正试图编写我的第一个回指宏,但遇到了一个问题。我正在使用sblc和粘液 当回指宏在另一个包中展开时,其符号将以定义它的包作为前缀(即,它们变成Common lisp 回指宏符号的前缀来自另一个包,如何去掉它?,common-lisp,Common Lisp,我正试图编写我的第一个回指宏,但遇到了一个问题。我正在使用sblc和粘液 当回指宏在另一个包中展开时,其符号将以定义它的包作为前缀(即,它们变成tjb utilities::value,而不仅仅是value。发生了什么 PE> (macroexpand-1 '(act-if-key :pcram (get-node) (print value))) (IF (HAS-KEY? :PCRAM (GET-NODE)) (LET ((TJB-UTILITIES::KEY :PCRAM)
tjb utilities::value
,而不仅仅是value
。发生了什么
PE> (macroexpand-1 '(act-if-key :pcram (get-node) (print value)))
(IF (HAS-KEY? :PCRAM (GET-NODE))
(LET ((TJB-UTILITIES::KEY :PCRAM)
(TJB-UTILITIES::VALUE (GETHASH :PCRAM (GET-NODE))))
(PRINT VALUE)))
这是宏定义:
(defmacro act-if-key (key hashtable &body body)
`(if (has-key? ,key ,hashtable)
(let ((key ,key) (value (gethash ,key ,hashtable)))
,@body)))
如果我在值前加前缀,则它的工作正常:
(act-if-key :pcram (get-node) (print tjb-utilities::value))
; in: ACT-IF-KEY :PCRAM
; (LET ((TJB-UTILITIES::KEY :PCRAM)
; (TJB-UTILITIES::VALUE
; (GETHASH :PCRAM (PHILOSOPHY-EXPERIENCE::GET-NODE))))
; (PRINT TJB-UTILITIES::VALUE))
;
; caught STYLE-WARNING:
; The variable TJB-UTILITIES::KEY is defined but never used.
;
; compilation unit finished
; caught 1 STYLE-WARNING condition
"hello"
"hello"
这些包的定义如下:
(defpackage #:tjb-utilities
(:nicknames :tjb)
(:use #:cl)
(:export "HAS-KEY?" "KEY-VALUE-PAIRS" "ACT-IF-KEY" "TJB-MAKE-HASH-TABLE"))
(defpackage #:my-package
(:nicknames :pe)
(:use #:cl #:clsql #:tjb-utilities))
更新:将lambda列表中的键更改为中的键将无效
(defmacro act-if-key (key_in hashtable &body body)
`(if (has-key? ,key_in ,hashtable)
(let ((key ,key_in) (value (gethash ,key_in,hashtable)))
,@body)))
CL-USER>(包装中:tjb)
#
TJB>(如果键(键哈希表和正文)则取消宏操作
(let((值(实习生“值”))
`(如果(有键?、键、哈希表)
(let((key,key)(,value(gethash,key,hashtable)))
(@body)))
动作键
TJB>(宏扩展-1'(TJB:act if键:pcram(获取节点)(打印值)))
(如果(HAS-KEY?:PCRAM(GET-NODE))
(LET((键:PCRAM)(值(GETHASH:PCRAM(GET-NODE)))
(打印值)
T
TJB>(包装内:cl用户)
#
CL-USER>(宏扩展-1'(tjb:act if键:pcram(获取节点)(打印值)))
(IF(TJB-UTILITIES::HAS-KEY?:PCRAM(GET-NODE))
(LET((TJB-UTILITIES::KEY:PCRAM)(VALUE(GETHASH:PCRAM(GET-NODE)))
(打印值)
T
CL-USER>
我不确定我是否复制了您需要的所有内容,我对您打算如何使用“键”有点不清楚,所以我只对值
进行了复制,就像在使用宏的包中创建它一样。您可以自己决定是否需要对键
进行复制
上面将当前包中的符号value
绑定到gethash
将返回的任何内容。在原始版本中,您拥有宏用户提供的key
,因此我决定您不希望宏中有符号key
,只需要它的值
但是请稍等,也许会有更好的答案,也许你可以只
制作符号
而不是实习,然后以某种方式绑定。我不确定。你可以只导出“键和”值符号。这就是为什么:
请注意“it导出”
回指宏的要点是有意捕捉宏主体中未被宏调用方明确定义的某些符号(我理解这是定义上的极端立场)因此,任何使用回指宏的人都必须知道环境(身体)中引入了哪些符号这意味着,当这些符号名称被添加到环境中时,他们不应该感到惊讶。因此,我认为导出回指没有问题。谢谢,我在本例中的解决方案更像是一个学习练习,不确定我是否会使用此方法。在本例中,
INTERN
可能是正确的。如果您使用MAKE-SYMBOL
,您实际上是在使用一个不需要的符号,因此宏扩展中的值
不是宏用户传入的值。这种方式带来了悲伤和可怕的调试时间。最好的学习方法是了解在像这样的现实库中是如何完成的。
CL-USER> (in-package #:tjb)
#<PACKAGE "TJB-UTILITIES">
TJB> (defmacro act-if-key (key hashtable &body body)
(let ((value (intern "VALUE")))
`(if (has-key? ,key ,hashtable)
(let ((key ,key) (,value (gethash ,key ,hashtable)))
,@body))))
ACT-IF-KEY
TJB> (macroexpand-1 '(tjb:act-if-key :pcram (get-node) (print value)))
(IF (HAS-KEY? :PCRAM (GET-NODE))
(LET ((KEY :PCRAM) (VALUE (GETHASH :PCRAM (GET-NODE))))
(PRINT VALUE)))
T
TJB> (in-package #:cl-user)
#<PACKAGE "COMMON-LISP-USER">
CL-USER> (macroexpand-1 '(tjb:act-if-key :pcram (get-node) (print value)))
(IF (TJB-UTILITIES::HAS-KEY? :PCRAM (GET-NODE))
(LET ((TJB-UTILITIES::KEY :PCRAM) (VALUE (GETHASH :PCRAM (GET-NODE))))
(PRINT VALUE)))
T
CL-USER>
(defpackage :anaphora
7 (:use :cl)
8 (:export
9 #:it
10 #:alet
11 #:slet
12 #:aif
13 #:aand
14 #:sor
15 #:awhen
16 #:aprog1
17 #:acase
18 #:aecase
...etc.