macros - 诡计 `syntax-rules` : Misplaced Ellipsis in Form; How to Write this Macro with Two Ellipses?

标签 macros scheme guile syntax-rules

我正在或多或少地尝试通过 syntax-rules 重新创建一个 let 结构,但它似乎因使用两个省略号而被绊倒。

我试过这样写:

(define-syntax if-let
  (syntax-rules ()
    [(_ (([binding        value]  ...)
         ([binding2 funct value2])
         ([binding3       value3] ...)) then else) (let ([binding  value]  ...
                                                         [binding2 value2]
                                                         [binding3 value3] ...)
                                                     (if (funct binding2) then else))]))

我认为 [binding2 funct value2] 中间的不同模式能够根据模式明确区分第一个模式何时结束以及第二个模式何时结束开始,但我一直在找回标题中的错误。

预期的结果是能够做类似的事情

(if-let ([var1                  1]
         [diff null? '(1 2 3 4 5)]
         [var2                  2])
    var1
  var2)

并返回 2 但能够在 diff 之前和之后拥有尽可能多的 var ,因此变量的顺序最终,使用并不重要。

我是否遗漏了一些明显的东西?这种模式是否可以通过 hygenic 宏来实现?感谢您的帮助!

最佳答案

这可以通过辅助宏来实现,以执行查找 funct 所需的递归操作。中间的东西。

(if-let-helper processed-bindings processed-conditions input-binding-conditions then else)

当它重复出现时,它会传输 input-binding-conditions 中的信息进入 processed-bindingsprocessed-conditions ,停止时 input-binding-conditions是空的。

(define-syntax if-let-helper
  (syntax-rules ()
    [(_ ([bnd val] ...) (cnd ...) () then else)
     (let ([bnd val] ...)
       (if (and cnd ...) then else))]
    [(_ ([bnd val] ...) (cnd ...) ([binding value] . rest) then else)
     (if-let-helper ([bnd val] ... [binding value]) (cnd ...) rest then else)]
    [(_ ([bnd val] ...) (cnd ...) ([binding funct value] . rest) then else)
     (if-let-helper ([bnd val] ... [binding value]) (cnd ... (funct binding))
                    rest then else)]))

(define-syntax if-let
  (syntax-rules ()
    [(_ (binding-funct-value ...) then else)
     (if-let-helper () () (binding-funct-value ...) then else)]))

使用它:

> (if-let ([var1                  1]
           [diff null? '(1 2 3 4 5)]
           [var2                  2])
    var1
    var2)
2

为了解释这一点,我将逐步介绍此示例如何处理每个子句。它最初变成了这个 if-let-helper调用:

(if-let-helper
  ()
  ()
  ([var1                  1]
   [diff null? '(1 2 3 4 5)]
   [var2                  2])
  var1
  var2)

前两个列表一开始是空的,因为它还没有处理任何东西。

(if-let-helper
  ([var1                  1])
  ()
  ([diff null? '(1 2 3 4 5)]
   [var2                  2])
  var1
  var2)

此时它已经处理了第一个子句并将绑定(bind)值对添加到第一个“processed-bindings”列表。但是,没有 funct在第一个子句中,因此它没有向第二个“已处理条件”列表添加条件。

(if-let-helper
  ([var1                  1]
   [diff       '(1 2 3 4 5)])
  ((null? diff))
  ([var2                  2])
  var1
  var2)

此时它已经处理了前两个子句,并添加了一个(null? diff)。第二个列表的条件,因为它看到了 funct在第二个子句中。

(if-let-helper
  ([var1                  1]
   [diff       '(1 2 3 4 5)]
   [var2                  2])
  ((null? diff))
  ()
  var1
  var2)

此时它已经处理了所有三个子句,因此它符合基本情况并转换为最终的 let。和 if :

(let ([var1                  1]
      [diff       '(1 2 3 4 5)]
      [var2                  2])
  (if (and (null? diff))
      var1
      var2))

关于macros - 诡计 `syntax-rules` : Misplaced Ellipsis in Form; How to Write this Macro with Two Ellipses?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55733124/

相关文章:

macros - 在 make 目标中设置 C 宏?

functional-programming - 理解 Let/cc 和 throw in racket

scheme - 包括来自 Racket /方案中的文件

scheme - 更改 REPL 以显示用户名、主机名和当前工作目录?

operators - 方案:为什么在重新定义预定义运算符时会出现这种结果?

debugging - 如何防止 Guile 为每个错误启动调试器?

razor - Umbraco Razor html 转义问题

c - 从其定义文件外部重新定义宏

scheme - 如何在 Scheme Lisp 中将字符串转换为精确数字?

scripting - Tera Term Scripting,需要帮助开发宏