2014-11-23 49 views
0

我有一個替代符號的所有實例列表功能:如何通過引用SEXP宏觀

(defun replace-symbol-in-sexp-fn (symbol-to-replace new-symbol sexp) 
    (if (eq sexp nil) 
     sexp 
     (cons 
     (if (listp (car sexp)) 
      (replace-symbol-in-sexp-fn symbol-to-replace new-symbol (car sexp)) 
      (if (eq (car sexp) symbol-to-replace) 
       (setf (car sexp) new-symbol) 
       (car sexp))) 
     (replace-symbol-in-sexp-fn symbol-to-replace new-symbol (cdr sexp))))) 

(defmacro replace-symbol-in-sexp (symbol-to-replace new-symbol sexp) 
    `(replace-symbol-in-sexp-fn ,symbol-to-replace ,new-symbol ,sexp)) 

(macroexpand-1 (replace-symbol-in-sexp '+ '* (+ 2 3))) 
; => TYPE-ERROR "The value 5 is not of type LIST" if sexp has comma, 
; => UNBOUND-VARIABLE "The variable SEXP is unbound" if sexp has no comma 

我得到任何一個類型的錯誤或試圖評估時未定義變量錯誤最後的表達,取決於sexp是否在最後一行中是否逗號。我測試過並更換符號功能於SEXP-FN工作給予時說:

(replace-symbol-in-sexp-fn '+ '* '(+ 2 3)) ; => (* 2 3) 

我想現在宏產生這樣使得SEXP沒有被引用像'(+ 2 3),所以我可以用任意的lisp代碼運行replace-symbol-in-sexp-fn。很顯然,我可以評估和傳遞引用到SEXP替代符號功能於SEXP-FN,如:

(eval (replace-symbol-in-sexp-fn '+ '* '(+ 2 3)) 

但是,這是一個笨拙的嘗試模仿宏,所以我寧願實際上只使用一個宏。有沒有一種乾淨的方式來做我想用宏做的事情?我錯過了什麼?

+0

「我得到一個類型錯誤或未定義變量錯誤」我沒有看到這些問題中的任何一個。你能舉一個例子嗎? – 2014-11-24 03:23:24

+0

用精確的結果進行編輯。 – cosmicexplorer 2014-11-25 13:04:21

回答

1

所以你重新實現了Common Lisp函數nsubstsubst是正常版本,並且n表示它是破壞性版本(不包括)。

請注意,在便攜式Common Lisp中,修改文字數據並不是一個好主意。效果不明確。忽略這一段時間:

(macroexpand-1 (replace-symbol-in-sexp '+ '* (+ 2 3))) 

但可能你想要宏展開表達式而不是結果?可能應該是:

(macroexpand-1 '(replace-symbol-in-sexp '+ '* (+ 2 3))) 

但是這個宏是沒有意義的。生成的代碼是錯誤的,因爲最後一個參數不計算爲列表。宏必須創建有用的代碼。正如你看到的最後一個表達式沒有被引用,這是沒有意義的。

CL-USER 14 > (macroexpand-1 '(replace-symbol-in-sexp '+ '* (+ 2 3))) 
(REPLACE-SYMBOL-IN-SEXP-FN (QUOTE +) (QUOTE *) (+ 2 3)) 

讓我們介紹報價:

(defmacro replace-symbol-in-sexp (symbol-to-replace new-symbol sexp) 
    `(replace-symbol-in-sexp-fn ,symbol-to-replace ,new-symbol ',sexp)) 

CL-USER 17 > (macroexpand-1 '(replace-symbol-in-sexp '+ '* (+ 2 3))) 
(REPLACE-SYMBOL-IN-SEXP-FN (QUOTE +) (QUOTE *) (QUOTE (+ 2 3))) 

是宏觀有用嗎?我有我的懷疑。

+0

這很有幫助;我沒有意識到我可以在這樣的逗號前加上一個引號。 你對它的效用有什麼疑問? – cosmicexplorer 2014-11-24 06:48:52

+0

@cosmicexplorer我無法肯定地說,但我期望Rainer的觀點是**替換symbol-in-sexp **可能並不是那麼有用,因爲正如Rainer指出的那樣,本質上** subst **或** nsubst **。 – 2014-11-25 13:14:28

+0

@JoshuaTaylor什麼是一個宏,它只是增加了對第三個參數有用的引用?爲什麼不直接使用該功能? – 2014-11-25 13:55:27

1

看來你不想擴展到函數調用,而是使用函數來擴展你的代碼。你不應該引用它,那麼:

(defmacro replace-symbol-in-sexp (symbol-to-replace new-symbol sexp) 
    (replace-symbol-in-sexp-fn symbol-to-replace new-symbol sexp)) 

我有你只是試圖重新實現類似symbol-macrolet的印象。

+0

好吧,我不知道這些東西已經有了函數,因爲當我搜索「在sexp中替換符號」時,我無法在CLHS中找到這些東西的參考。 – cosmicexplorer 2014-11-24 06:50:54