【问题标题】:Difference between an implementation of 'when' as a function vs. as a macro“when”作为函数的实现与作为宏的实现之间的区别
【发布时间】:2016-11-02 05:35:55
【问题描述】:

'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) (显示 i))

;中止!:超出最大递归深度

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

【问题讨论】:

    标签: macros scheme mit-scheme


    【解决方案1】:

    方案具有严格的语义。

    这意味着函数的所有参数都在函数应用于它们之前进行评估。

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

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

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

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

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

    然后整个事情被评估,这意味着(loop (+ i 1))只有在条件为真时才会被评估。

    【讨论】:

    • 很好的解释!您能否澄清为什么 (loop (+ i 1)) 仅在条件为真时才被评估?对我来说,它看起来只有在条件为假时才会被评估,因为“when”宏似乎没有在其 if 语句中“使用”循环。
    • @wes 循环是my-when 宏中“..:”的一部分。我希望编辑有所帮助。
    【解决方案2】:

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

    1. 评估(&lt; i to)
    2. 评估b1 ...的扩展结果
    3. 评估(loop (+ i 1))
    4. 评估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))))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-01
      • 2018-10-23
      • 2023-03-06
      • 2012-11-15
      • 1970-01-01
      • 2016-06-18
      • 2021-09-19
      • 2016-09-14
      相关资源
      最近更新 更多