2012-11-03 17 views
3

我試圖寫我的第一個照應宏,並且遇到問題。我正在使用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))) 

它的工作correclty如果我的前綴值:

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

最好的學習方法是瞭解它是如何在真實的圖書館中完成的,如[回指](http://www.common-lisp.net/project/anaphora/)。 – Daimrod

回答

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> 

不知道如果我複製你所需要的全部,並且我對你打算如何使用「key」有點模糊,所以我只在value的方式上做了它,因爲它將在使用宏的包中創建。你可以自己計算一下,不管你是否需要相同的key

上面將當前包中的符號value綁定到任何gethash將返回。在你的原始版本中,你有宏由用戶提供的key,所以我決定你不想在宏內部有一個符號key,只是它的價值。

但等一下,也許會有更好的答案,也許你可以只是make-symbol它而不是實習,然後以某種方式綁定它。我不確定。

+0

謝謝,在這種情況下,我的解決方案更多的是學習練習,不確定我是否會在任何地方使用 – tjb

+0

在這種情況下,'INTERN'可能是正確的。如果使用'MAKE-SYMBOL',則實際上使用了一個未插入的符號,所以宏擴展中的'value'不是宏用戶傳入的'value'。這種方式令人感到悲傷和可怕的調試時間。 – Vatine

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. 

注意「導出。

宏指令的一個要點是有意識地捕捉宏中沒有被宏調用者明確定義的特定符號(我理解這是對定義的極端立場)。因此,任何使用照應宏的人都需要知道將哪些符號引入該宏的環境(主體)。這意味着當這些符號名稱添加到環境中時,他們不應該感到驚訝。所以我覺得出口回指沒有問題。