回指宏符号具有来自不同包的前缀,我该如何摆脱它?

时间:2012-11-03 15:33:27

标签: 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 (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列表中的键更改为key_in无效

(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)))

2 个答案:

答案 0 :(得分:3)

您只需导出'键和'值符号即可。 Anaphora就是这样做的:

(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.

请注意'it export。

照应宏的意义在于故意捕获宏的主体中某些未被宏的调用者明确定义的符号(我理解这是对定义的极端立场)。因此,任何使用照应宏的人都需要知道哪些符号被引入该宏的环境(正文)。这意味着当这些符号名称添加到环境中时,他们不应该感到惊讶。所以我认为导出回指没有问题。

答案 1 :(得分:2)

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> 

不确定我是否复制了你需要的所有内容,而且我对你打算如何使用“密钥”有点模糊,所以我只是按照value的方式做了它。在包中创建,使用宏。无论你是否需要key,都可以自己解决。

上面将当前包中的符号value绑定到gethash将返回的任何内容。在您的原始版本中,您有宏的用户提供key,因此我决定您不希望宏中包含符号key,只是它的值。

但是等一下,也许会有一个更好的答案,也许你只能make-symbol而不是实习,然后以某种方式绑定它。我不确定。