在Scheme中定义一个返回表达式运算符的宏



我正在寻找这样的功能:

(op (+ 1 2))
; +

我似乎一辈子都不知道如何使用define-macro来做到这一点。有什么帮助吗?

谢谢,

编辑:

这特别令人困惑,因为我可以做:

(car '(+ 1 2))
; +

但如果我这样做:

(define-macro (op expr)
(car expr))
(op '(+ 1 2))

它不起作用。

OP将宏op定义为一个函数,但Lisp宏不能以这种方式工作。对宏窗体进行求值以生成一个新窗体,该窗体替代原始宏调用,但宏参数被传递到未求值的宏体中。这意味着在op的宏主体内,car不对数据(+ 1 2)进行操作,而是对数据(quote (+ 1 2))进行操作。

op的目标不是计算(car expr),而是生成形式(car expr)(其中expr被宏参数的值替换(,然后在宏展开后在REPL中对其进行计算。可以使用list:

(define-macro (opl expr)
(list 'car expr))

或使用准引号

(define-macro (opq expr)
`(car ,expr))

这里,后引号引入了列表的模板,逗号导致符号expr被评估为其值((quote (+ 1 2))(,并且结果被插入到列表中。一个简单引用的列表,例如'(car expr)将评估为列表(car expr),其中expr只是符号expr。使用准引号,,expr计算为宏调用中提供的参数值,例如`(car ,expr)->(car '(+ 1 2))。注意,当expr'(+ 1 2)时,(list 'car expr)产生与(opl '(+ 1 2))相同的形式

这种define-macro语法几乎与Common Lisp的传统defmacro语法相同,不同之处在于defmacro的宏名称位于形式参数列表之前,例如(defmacro op (expr) ;...)define-macro在Standard Scheme中不可用,但一些Scheme实现确实支持它。Guile Scheme同时支持defmacrodefine-macro。以上两个宏解决方案都适用于Guile:

scheme@(guile-user)> (opl '(+ 1 2))
$2 = +
scheme@(guile-user)> (opq '(+ 1 2))
$3 = +

最新更新