2011-10-12 59 views
8

我试图创造MIT计划这个简单的(Common Lisp中)宏相当于百思不得其解:如何编写一个MIT Scheme宏来返回一个lambda表单?

(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的宏系统上引用了很好的教程(不是引用),它以小的简单例子开始,并具有充足的注释,并且特别显示了如何转换反引号逗号样式的LISP宏(对我而言高度直观)到Scheme的语法宏观系统会很好。

回答

4

您可以通过使用explicit-renaming macros基本上做同样的事情,与defmacro 。唯一重要的区别是您必须自行解构输入表单:

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

ER实现(MIT Scheme支持)。 :-) –

+1

@ ChrisJester-Young感谢您的错误修复。 :) –

+0

+1。谢谢一堆。 define-syntax完全令人困惑,但我怀疑它非常强大,我想更好地学习它,有任何提及它的提法?我接受你的答案,因为它提供了一个在MIT计划中可用的函数,我希望我也可以接受克里斯的答案,因为它也指出solv也必须是一个语法规则宏。 – Bogatyr

7

它不能在syntax-rules中完成。故事结局。

将输入表达式中的任意标识符(x)输入到输出表达式中需要破坏卫生,并且syntax-rules没有提供任何方法来打破卫生。您将需要使用较低级别的宏系统来执行此操作。麻省理工学院计划使用显式重命名(见马蒂亚斯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))))) 
+0

+1非常感谢您的回答,并指出solv也必须是宏。首先,宏是非常棘手的,但Scheme语法 - *宏可能是迄今为止我在语言中遇到的最难的事情,我一直在编程(大多是蓝调,但我在CL中完成了我的硕士论文)30+年份。 – Bogatyr

+0

@Bogatyr:等你继续下去。 ;-)(尽管严格地说,尽管R5RS规范在50页之内,Scheme仍然是一门相当大的语言。) –

相关问题