【问题标题】:Guile `syntax-rules`: Misplaced Ellipsis in Form; How to Write this Macro with Two Ellipses?Guile `syntax-rules`:表格中的省略号;如何用两个椭圆编写这个宏?
【发布时间】:2019-04-17 17:32:38
【问题描述】:

我试图或多或少地通过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 之前和之后拥有尽可能多的vars,因此最终使用的变量的顺序并不重要。

我是否遗漏了一些明显的东西?这种模式是否可以用卫生宏来完成?感谢您的帮助!

【问题讨论】:

    标签: macros scheme guile syntax-rules


    【解决方案1】:

    这可以通过辅助宏来实现,以执行必要的递归来找到中间的 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)
    

    此时它已经处理了第一个子句并将绑定值对添加到第一个“已处理绑定”列表中。但是,第一个子句中没有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)
    

    此时它已经处理了所有三个子句,因此它达到了基本情况并转换为最终的letif

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

    【讨论】:

    • 天哪,我以为我是在你发帖后才回复的;对此我很抱歉。非常感谢您的回答;它非常有用,详细且易于处理。另外,它帮助我解决了我的问题。非常感谢!
    猜你喜欢
    • 2010-09-12
    • 1970-01-01
    • 2019-04-28
    • 2013-12-05
    • 2018-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多