我正在寻找这样的功能:
(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同时支持defmacro
和define-macro
。以上两个宏解决方案都适用于Guile:
scheme@(guile-user)> (opl '(+ 1 2))
$2 = +
scheme@(guile-user)> (opq '(+ 1 2))
$3 = +