'when' 作为函数与作为宏的实现之间的区别

Difference between an implementation of 'when' as a function vs. as a macro

'when' 的这些实现之间到底有什么不同?

(define-syntax when
  (syntax-rules ()
    ((_ pred b1 ...)
     (if pred (begin b1 ...)))))

对比

(define (my-when pred b1 ...)
  (if pred (begin b1 ...)))

例如在这个for循环宏中使用'my-when'时:

(define-syntax for
  (syntax-rules ()
    ((_ (i from to) b1 ...)
     (let loop((i from))
       (my-when (< i to)
                  b1 ...
                  (loop (+ i 1)))))))

发生错误:

(for (i 0 10) (display i))

; Aborting!: maximum recursion depth exceeded

我不认为'when'可以作为一个函数来实现,但我不知道为什么...

如果像您一样将 when 实现为一个过程,那么所有参数都会被求值。在您的 for 实施中,评估将按如下方式处理:

  1. 评价(< i to)
  2. 评估b1 ...
  3. 的扩展结果
  4. 评估(loop (+ i 1)) <- 这里进入无限循环!
  5. 评价my-when

项目 1-3 可以是相反的或未定义的顺序,具体取决于您的实施,但要点是 nr。 4. 如果my-when作为一个宏来实现,那么这个宏是第一个被求值的。

如果你真的需要用一个程序来实现,那么你需要使用诸如thunk之类的延迟技巧。例如:

(define (my-when pred body) (if (pred) (body)))
(my-when (lambda () (< i 10)) (lambda () (display i) (loop (+ i 1))))

方案具有严格的语义。

这意味着函数的所有参数在函数应用到它们之前都会被求值。

宏获取源代码并生成源代码 - 它们不评估任何参数。

(或者,好吧,我想他们有,但他们的参数是语法 - 语言元素 - 而不是你通常认为的值,例如数字或字符串。宏编程是元编程。重要的是请注意您正在编程的级别。)

在您的示例中,这意味着当 my-when 是一个函数时,必须在 my-when 应用于它之前评估 (loop (+ i 1))
这导致无限递归。

当它是宏时,my-when 形式首先被替换为等价的 if-形式

 (if (< i to)
     (begin
         b1 ...
         (loop (+ i 1))))

然后对整个事情进行评估,这意味着 (loop (+ i 1)) 仅在条件为真时才进行评估。