2014-11-23 48 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