Scheme R5RS 示例中的语法规则卫生宏调用中缺少参数

Missing argument in syntax-rules Hygienic macro call from Scheme R5RS example

我还有一个关于 Scheme 中卫生宏的问题,请考虑 R5RS

中的示例
(let-syntax ((when (syntax-rules ()
                     ((when test stmt1 stmt2 ...)
                      (if test
                          (begin stmt1
                                 stmt2 ...))))))
  (let ((if #t))
    (when if (set! if 'now))
    if))

如果模式有 3 个参数和省略号可以匹配空列表,为什么会匹配?

它使用 2 个参数 if(set! if 'now) 调用。 ... 应该绑定到什么,如果 stmt2 可以绑定到空列表?这是一种非 Lispy if ... 什么都不是。是真的吗?

在这种情况下,when 的扩展应该是什么? stmt2 的值是多少?

为什么这不起作用但第一个代码起作用?

(let-syntax ((when (syntax-rules ()
                     ((when test stmt1 stmt2 ...)
                      (if test
                          (begin stmt1
                                 stmt2 ...))))))
    (when if 10))

它在 Kawa 中有效但在 Guile 中无效,这是 Guile 中的错误吗,它实际上应该像在 Kawa 中一样工作?

还有一个问题,为什么它不计算为 nil?如果列表中 10 之后的下一个元素是 nil 那么 stmt2 应该是 nil? R5RS 在这方面不是很有帮助。

我问这个是因为我刚刚在 LIPS Scheme 中为我的宏系统完成了重命名方案,当我进行模式匹配时,我得到了 stmt2nil 的比较以及还剩下...。在这种情况下,是否应该忽略 ...stmt2 应该是 nil?即使模式中少了一个符号,它也应该匹配吗?这真是令人困惑。

最后一段代码的扩展应该是什么?

编辑:

再想想

(let-syntax ((when (syntax-rules ()
                     ((when test stmt1 . stmt2)
                      (if test
                          (begin stmt1
                                 stmt2))))))
    (when if 10))

这在 Kawa 和 return nil 中如预期的那样有效,但在 Guile 中它抛出异常,我认为 Kawa Scheme 在以下规范中更好。

但为什么在没有足够参数的情况下它甚至匹配模式?

是的。我们有一个修饰符 ... 来改变前面元素的含义,这是非常不灵活的。例如。 something ... 基本上类似于 . something 除了它适用于这样的结构:

(define-syntax my-let
  (syntax-rules ()
    ((_ ((a b) ...)
        body1 bodyn ...)
     ((lambda (a ...) 
        body1 bodyn ...) 
      b ...))))

注意我使用 body1 ro 要求正文中至少有一个表达式,因为 bodyn ... 可以是零个或多个元素。这将变成:

(my-let ()
  test)
==> 
((lambda () test))

以及

(my-let ((a b) (c d))
  test1 test2)
==> 
((lambda (a c)
   test1 test2)
 b 
 d)

我的示例不能用 cons 语法重写,但基本上使用 . 与模式中的其余参数和引号中的 . 的工作方式相同:

'(a b . (c d)) 
; ==> (a b c d)

您的 when 无法处理多个表达式。 例如。

(let-syntax ((when (syntax-rules ()
                     ((when test stmt1 . stmt2)
                      (if test
                          (begin stmt1
                                 stmt2))))))
    (define if #t)
    (when if (display 'true) #t))

假设所有报表绑定也存在于 r5rs: 前缀下。扩展将变为:

(r5rs:if if
         (begin (display 'true)
                (#t)))
; ERROR: Application not a procedure: #t

这是正确的:

(let-syntax ((when (syntax-rules ()
                     ((when test stmt1 . stmt2)
                      (if test
                          (begin stmt1
                                 . stmt2))))))
    (define if #t)
    (when if (display 'true) #t))
; ==> #t (prints true)