如何编写 MIT Scheme 宏来返回 lambda 形式?

发布于 2024-12-09 12:12:13 字数 981 浏览 0 评论 0原文

我对在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

往事风中埋 2024-12-16 12:12:13

它不能在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)))))

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, and syntax-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 use syntax-case, you can do it thus:

(define-syntax funcify
  (lambda (stx)
    (syntax-case stx ()
      ((_ body)
       (with-syntax ((x (datum->syntax stx 'x)))
         #'(lambda (x)
             body))))))

The key is the (datum->syntax stx 'x) bit, which injects the symbol x as if it were in the syntactic context of the funcify invocation.

By the way, your solv must also be a macro, not a procedure, but at least it can be a syntax-rules macro:

(define-syntax solv
  (syntax-rules ()
    ((_ lhs rhs) (solve (funcify lhs) (funcify rhs)))))
开始看清了 2024-12-16 12:12:13

您可以使用 显式重命名宏。唯一显着的区别是您必须自己解构输入表单:

(define-syntax funcify
  (er-macro-transformer
    (lambda (form rename cmp)
      (let ((exp (cadr form)))
        `(,(rename 'lambda) (x) ,exp)))))

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:

(define-syntax funcify
  (er-macro-transformer
    (lambda (form rename cmp)
      (let ((exp (cadr form)))
        `(,(rename 'lambda) (x) ,exp)))))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文