'当'的实施之间的差异作为一个函数而不是宏

时间:2016-11-02 05:35:56

标签: macros scheme mit-scheme

'当'这些实现之间究竟有什么不同?

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

VS。

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

例如,当' my-when'用于此for循环宏:

(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))

     

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

我不认为&#39;何时&#39;可以作为一个函数实现,但我不知道为什么......

2 个答案:

答案 0 :(得分:0)

如果将when实现为与您一样的过程,则会评估所有参数。在for实施中,评估将按以下方式处理:

  1. 评估(< i to)
  2. 评估b1 ...
  3. 的扩展结果
  4. 评估(loop (+ i 1))&lt; - 这里进入无限循环!
  5. 评估my-when
  6. 项目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))))
    

答案 1 :(得分:0)

Scheme具有严格的语义。

这意味着在将函数应用于函数之前,将评估所有函数的参数。

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

(或者,好吧,我想他们这样做了,但他们的参数是语法 - 语言元素 - 而不是你通常认为的值,如数字或字符串。宏编程是元编程。它是&#39; s重要的是要知道你在哪个级别编程。)

在您的示例中,这意味着当type ActionA = { type: 'A', a: number }; type ActionB = { type: 'B', b: string }; type Action = ActionA | ActionB; type State = number; function reducer(state: State, action: Action): State { switch(action.type) { case 'A' : return action.a case 'B' : return action.b.length default : (action: null) // check for exhaustivity throw `unknown action` } } 是一个函数时,my-when必须先评估(loop (+ i 1))才能应用my-when
这导致无限递归。

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

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

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