2013-02-27 83 views
1

我對傳遞給宏的參數如何得到評估有疑問,細節如下。在宏體內傳遞參數的評估

這個宏定義

(defmacro test-macro (xlist) 
    `(* ,@xlist)) 

並沒有這個全局變量(defvar *test-list* '(1 100 2 200))

*test-list*傳遞給這個宏(test-macro *test-list*),返回此錯誤 -

value *TEST-LIST* is not of the expected type LIST. 
    [Condition of type TYPE-ERROR] 

但如果功能被修改爲這個,返回

(defmacro test-macro (xlist) 
    `(,@xlist)) ;; removed the * operator 

(test-macro *test-list*)名單將返回(1 100 2 200)

所以我懷疑爲什麼,@xlist在第一種情況下沒有得到評估,即應用了*操作符。任何幫助,高度讚賞。

回答

4

調試宏時,正確的方法是使用macroexpand,而不是評估宏的形式。例如,在你的情況下:

(defmacro test-macro1 (xlist) `(* ,@xlist)) 
(macroexpand '(test-macro1 foo)) 
==> (* . FOO) 
(defmacro test-macro2 (xlist) `(,@xlist)) 
(macroexpand '(test-macro2 foo)) 
==> FOO 

既不可能是你想要的。

+0

非常感謝。宏觀膨脹是超級有用的.. – 5Fists 2013-02-27 15:39:54

+0

@ 5fists有一個熱鍵macroexpand在粘液;這是1,slimv – 2013-02-28 06:56:31

3

令人困惑的是宏是一個預處理器:它沒有內置機制來知道運行時值。所以,當你使用術語:

(test-macro test-list) 

所有宏看到的是標識test-list:它不知道的前期的運行值是一個列表,只有源程序已經使用這種變量標識符。

宏是源到源重寫器:它不知道程序的動態。一個更聰明的編譯器可能會看到測試列表是一個常量並進行內聯,但宏擴展器並不聰明。

你可以做什麼可能是這樣的:

(defmacro test-macro (xlist) 
    (cond 
    (;; If we see test-macro is being used with a quoted list of things 
    ;; then we can rewrite that statically. 
    (and (pair? xlist) 
      (eq? (car xlist) 'quote) 
      (list? (cadr xlist))) 
    `(list 'case-1 (* ,@(cadr xlist)))) 

    (;; Also, if we see test-macro is being used with "(list ...)" 
    ;; then we can rewrite that statically. 
    (and (pair? xlist) 
      (eq? (car xlist) 'list)) 
    `(list 'case-2 (* ,@(cdr xlist)))) 

    (else 
    ;; Otherwise, do the most generic thing: 
    `(list 'case-3 (apply * ,xlist))))) 



;; This hits the first case: 
(test-macro '(3 4 5)) 

;; ... the second case: 
(test-macro (list 5 6 7)) 

;; ... and the third case: 
(defvar test-list '(1 100 2 200)) 
(test-macro test-list) 

至於你的第二個版本:宏:

(defmacro test-macro (xlist) 
    `(,@xlist)) 

等同於:

(defmacro test-macro (xlist) 
    xlist) 

所以這就是爲什麼你沒有收到您在第一版中收到的錯誤。

+0

感謝您在這樣的細節解釋它。在您的代碼中使用的一些函數在我使用的Common Lisp實現中不可用。不能說我完全理解您的代碼,但沒有幾個重要的點對我進一步學習Lisp非常有用。似乎我有很長的路要走:)。 – 5Fists 2013-02-27 15:34:48