我很困惑,试图在MIT Scheme中创建相当于这个简单的(在Common Lisp中)宏:
(defmacro funcify (exp)
`(lambda (x) ,exp))
这是一个简单的个人项目,一个基于第二次SICP讲座中建立的功能的数值方程求解器。我不在乎这个宏不是“安全”或“卫生”,或者如果exp引用除'x之外的任何符号,它将捕获变量。我希望能够写
(solv '(* 60 x) '(* 90 (- x 1)))
其中solv是:
(define (solv lh-exp rh-exp)
(solve (funcify lh-exp) (funcify rh-exp)))
而不必输入
(solve (lambda (x) (* 60 x)) (lambda (x) (* 90 (- x 1))))
但无法弄清楚如何使用MIT Scheme语法规则来做到这一点。
我试过这个,但它不起作用:
(define-syntax funcify
(syntax-rules ()
((funcify y) (lambda (x) y))))
;Value: funcify
(funcify x)
;Value 17: #[compound-procedure 17]
((funcify x) 10)
;Unbound variable: x
我尝试过其他可能不值得提及eval
的事情,但无济于事。
另外,在Scheme的宏系统上引用了很好的教程(不是引用),从小的简单示例开始并构建,有充分的注释,特别是展示了如何转换backquote-comma样式的LISP宏(这对我来说很高直观)到Scheme的语法宏系统会很棒。
答案 0 :(得分:7)
无法在syntax-rules
中完成。故事结束。
在输出表达式中注入任意标识符(x
)需要打破卫生,syntax-rules
不提供任何破坏卫生的方法。您需要使用较低级别的宏系统来执行此操作。 MIT Scheme使用显式重命名(请参阅Matthias Benkard的回答),但对于使用syntax-case
的其他Scheme实现,您可以这样做:
(define-syntax funcify
(lambda (stx)
(syntax-case stx ()
((_ body)
(with-syntax ((x (datum->syntax stx 'x)))
#'(lambda (x)
body))))))
密钥是(datum->syntax stx 'x)
位,它注入符号x
,就好像它位于funcify
调用的语法上下文中一样。
顺便说一下,您的solv
也必须是一个宏,而不是一个过程,但至少它可以是一个syntax-rules
宏:
(define-syntax solv
(syntax-rules ()
((_ lhs rhs) (solve (funcify lhs) (funcify rhs)))))
答案 1 :(得分:4)
您可以使用explicit-renaming macros与defmacro
基本相同。唯一重要的区别是您必须自己解构输入表单:
(define-syntax funcify
(er-macro-transformer
(lambda (form rename cmp)
(let ((exp (cadr form)))
`(,(rename 'lambda) (x) ,exp)))))