9

我试图在 MIT 方案中创建与这个微不足道的(在 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 方案语法规则来做到这一点。

我已经尝试过了,但它不起作用:

(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 宏(对我来说非常直观)转换为Scheme 的语法宏系统会很棒。

4

2 回答 2

7

它不能在syntax-rules. 故事结局。

将任意标识符(x在您的情况下为 )注入输出表达式需要破坏卫生,并且syntax-rules不提供任何破坏卫生的方法。您将需要使用较低级别的宏系统来执行此操作。MIT Scheme 使用显式重命名(请参阅 Matthias Benkard 的回答),但对于使用 的其他 Scheme 实现syntax-case,您可以这样做:

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

关键是位,它像在调用的句法上下文中一样(datum->syntax stx 'x)注入符号。xfuncify

顺便说一句,你solv也必须是一个宏,而不是一个过程,但至少它可以是一个syntax-rules宏:

(define-syntax solv
  (syntax-rules ()
    ((_ lhs rhs) (solve (funcify lhs) (funcify rhs)))))
于 2011-10-12T17:44:11.720 回答
4

你可以做与defmacro使用显式重命名宏基本相同的事情。唯一显着的区别是您必须自己解构输入表单:

(define-syntax funcify
  (er-macro-transformer
    (lambda (form rename cmp)
      (let ((exp (cadr form)))
        `(,(rename 'lambda) (x) ,exp)))))
于 2011-10-12T17:52:49.097 回答