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

Jay*_*Jay 2 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)))))))))
Run Code Online (Sandbox Code Playgroud)

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

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

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

(let ((if 'x))
  (for i 1 5
       (print i)))
Run Code Online (Sandbox Code Playgroud)

它开始计数,永不停止.

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

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

(let ((#:start15 1)
      (#:stop16 5))
 ((letrec ((#:loop17 (lambda (i) 
                       (if (< i #:stop16) 
                           (begin (print i)
                                  (#:loop17 (+ 1 i))))))) 
     #:loop17)
   #:start15))))
Run Code Online (Sandbox Code Playgroud)

而在Gauche:

(let ((:start4 1)
      (:stop5 5))
  (let :loop6 ((i :start4))
       (if (< i :stop5)
           (begin (print i)
                  (:loop6 (+ 1 i))))))
Run Code Online (Sandbox Code Playgroud)

但是,如果我将符号插入到符号x所在的if位置,我会使用一个特殊形式或程序的符号...为什么解释器只是停下来抱怨?

Eli*_*lay 5

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

但更重要的是:

    define-macro 对你的健康有害