Guile `syntax-rules`:形式中错位的省略号;如何用两个省略号写这个宏?
Guile `syntax-rules`: Misplaced Ellipsis in Form; How to Write this Macro with Two Ellipses?
我正在或多或少地尝试通过 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-bindings
和 processed-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)
此时它已经处理了第一个子句并将绑定值对添加到第一个 "processed-bindings" 列表。但是,第一个子句中没有 funct
,因此它没有向第二个 "processed-conditions" 列表添加条件。
(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))
我正在或多或少地尝试通过 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-bindings
和 processed-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)
此时它已经处理了第一个子句并将绑定值对添加到第一个 "processed-bindings" 列表。但是,第一个子句中没有 funct
,因此它没有向第二个 "processed-conditions" 列表添加条件。
(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))