Scheme中使用define-macro进行变量捕获的机制

时间:2010-10-08 20:01:31

标签: macros scheme

考虑这个不卫生的Scheme宏:

(define-macro for
  (lambda (i i1 i2 . body)
    (let ((start (gensym))
          (stop  (gensym))
          (loop  (gensym)))
      `(let ((,start ,i1)
             (,stop  ,i2))
         (let ,loop ((,i ,start))
              (if (< ,i ,stop)
                  (begin ,@body
                         (,loop (+ 1 ,i)))))))))

它实现了一个for循环(我正在使用Gauche和Gambit):

> (for i 1 5
       (print i))
1
2
3
4
#

但是,由于我没有重命名if,这肯定会破坏:

(let ((if 'x))
  (for i 1 5
       (print i)))

它开始计数,永不停止。

现在,我已经尝试过宏扩展这个并且无法确切地看到它为什么循环而不仅仅是发出错误信号。

Gambit的扩展(没有if重新定义部分)是:

(let ((#:start15 1)
      (#:stop16 5))
 ((letrec ((#:loop17 (lambda (i) 
                       (if (< i #:stop16) 
                           (begin (print i)
                                  (#:loop17 (+ 1 i))))))) 
     #:loop17)
   #:start15))))

在Gauche:

(let ((:start4 1)
      (:stop5 5))
  (let :loop6 ((i :start4))
       (if (< i :stop5)
           (begin (print i)
                  (:loop6 (+ 1 i))))))

但如果我在x所在的地方插入符号if,我会使用符号,其中需要特殊的表格或程序......为什么翻译不会停止并抱怨这个?

1 个答案:

答案 0 :(得分:5)

您将if绑定为普通值,这意味着(if blah blah blah)不再是特殊形式 - 这意味着它正在转向函数应用程序。这个应用程序显然会导致错误,但由于Scheme是严格的,您需要在尝试应用它之前评估此函数的参数。 (一旦函数表达式求值为非函数,它就会因错误而停止,但实现很少这样做。)因此,首先计算递归循环调用 - 但这会导致另一个if函数调用,等

但更重要的是:

define-macro对您的健康有害