如何编写 MIT Scheme 宏来返回 lambda 形式?
我对在 MIT 方案中尝试创建这个简单的(在 Common Lisp 中)宏的等价物感到困惑:
(defmacro funcify (exp)
`(lambda (x) ,exp))
这是一个简单的个人项目,一个基于第二个 SICP 讲座中构建的函数的数值方程求解器。我不在乎这个宏是否“安全”或“卫生”,或者如果 exp 引用除 'x.x' 以外的任何符号,它会捕获变量。我希望能够写出
(solv '(* 60 x) '(* 90 (- x 1)))
solv is: 的位置
(define (solv lh-exp rh-exp)
(solve (funcify lh-exp) (funcify rh-exp)))
,而不必输入
(solve (lambda (x) (* 60 x)) (lambda (x) (* 90 (- x 1))))
But can't find out how to do this using 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宏系统的优秀教程(不是参考资料),这些教程从简单的小示例开始,并带有充足的注释,特别展示了如何将反引号逗号样式的LISP宏(对我来说非常直观)转换为方案的语法宏系统会很棒。
I'm baffled by trying to create the equivalent of this trivial (in Common Lisp) macro in MIT Scheme:
(defmacro funcify (exp)
`(lambda (x) ,exp))
This is for a simple personal project, a numerical equation solver based on the functions built in the second SICP lecture. I don't care that this macro is not "safe" or "hygienic" or will capture a variable if the exp references any symbols other than 'x. I'd like to be able to write
(solv '(* 60 x) '(* 90 (- x 1)))
where solv is:
(define (solv lh-exp rh-exp)
(solve (funcify lh-exp) (funcify rh-exp)))
instead of having to type
(solve (lambda (x) (* 60 x)) (lambda (x) (* 90 (- x 1))))
But can't figure out how to do this using MIT Scheme syntax-rules.
I've tried this but it doesn't work:
(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
I've tried other things probably not worth mentioning involving eval
but to no avail.
Also, references to good tutorials (not references) on Scheme's macro system that start with small simple examples and build up, with ample commentary, and in particular show how to convert backquote-comma style LISP macros (which to me are highly intuitive) to Scheme's syntax macro system would be great.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
它不能在
syntax-rules
中完成。故事结束。将任意标识符(
x
,在您的情况下)注入到输出表达式中需要破坏卫生,并且syntax-rules
不提供任何破坏卫生的方法。您将需要使用较低级别的宏系统来执行此操作。 MIT Scheme 使用显式重命名(参见 Matthias Benkard 的答案),但对于使用syntax-case
的其他 Scheme 实现,您可以这样做:关键是
(datum->syntax stx 'x)
位,它注入符号x
,就好像它位于funcify
调用的语法上下文中一样。顺便说一句,您的
solv
也必须是一个宏,而不是过程,但至少它可以是一个syntax-rules
宏:It cannot be done in
syntax-rules
. End of story.Injecting an arbitrary identifier (
x
, in your case) into the output expression requires breaking hygiene, andsyntax-rules
does not provide any means to break hygiene. You will need to use a lower-level macro system to do this. MIT Scheme uses explicit renaming (see Matthias Benkard's answer), but for other Scheme implementations that usesyntax-case
, you can do it thus:The key is the
(datum->syntax stx 'x)
bit, which injects the symbolx
as if it were in the syntactic context of thefuncify
invocation.By the way, your
solv
must also be a macro, not a procedure, but at least it can be asyntax-rules
macro:您可以使用 显式重命名宏。唯一显着的区别是您必须自己解构输入表单:
You can do basically the same thing as with
defmacro
by using explicit-renaming macros. The only significant difference is that you will have to destructure the input form yourself: