嵌套省略号宏在 Guile 和 Racket 中不起作用
Nested ellipsis macro doesn't work in Guile and Racket
我正在尝试创建一个简单的嵌套宏。它在我的 Scheme 实现中有效,但在 Guile 和 Racket 中无法 运行。
(define-syntax foo
(syntax-rules (:c)
((_ x ...)
(let-syntax ((bar (syntax-rules ::: (:c)
((_ x)
(print x))
((_ a b :::)
(begin
(display a)
(display " ")
(bar b :::))))))
(bar x ...)))))
- 诡计投掷:
syntax: missing ellipsis
- 球拍投掷:
missing ellipsis with pattern variable in template
我也试过 运行 在 Gambit 中,但那个只是抛出:
Unbound variable: define-syntax
我猜你需要使用库才能使用基本方案。
在 Checken Scheme 中,更新省略号后:
(define-syntax foo
(syntax-rules (:c)
((_ x ...)
(let-syntax ((bar (syntax-rules <:::> (:c)
((_ x)
(print x))
((_ a b <:::>)
(begin
(display a)
(display " ")
(bar b <:::>))))))
(bar x ...)))))
投掷:
template dimension error (too few ellipses?): x
这个宏有什么问题?为什么会抛出错误?
编辑:
看来这个模式是无效的:
(_ x ...)
但这是
(_ x y ...)
这是在某处指定的吗?为什么第一个语法无效?
为了完整起见,这段代码可以编译,但为什么第一个没有?
(define-syntax foo
(syntax-rules ()
((_ x y ...)
(let-syntax ((bar (syntax-rules <:::> ()
((_ x)
(print x))
((_ a b <:::>)
(begin
(display a)
(display " ")
(bar b <:::>))))))
(bar x y ...)))))
但是当尝试使用 foo
宏时它不起作用。它抛出:
unbound variable: bar
即使使用 letrec-syntax
.
外部语法规则中的此模式 (_ x ...)
会将模式变量 x 绑定到匹配列表中。这意味着,当 x
出现在模板中时,它后面必须(不一定直接)跟一个省略号。
这就是您从 Guile 和 Racket 中得到错误的原因。
现在考虑外部宏 (foo) 引入内部宏 (bar) 的情况,其定义包含省略号。当扩展器看到...
是属于外宏定义还是属于内宏定义?
使用的约定(至少是 Racket 和所有语法规则的 psyntax 派生实现)是 ...
属于外层。
为了产生“内部省略号”,需要“引用”。所以生成一个内部省略号,写成(... ...)
.
在实践中这可能很烦人,所以我经常将内部定义包装在
(with-syntax ((ooo (... ...))
code using ooo as an inner ellipsis here)
据我所知,您示例中的 (syntax-rules <:::> () etc)
是非标准的,因为语法是 (syntax-rules literals (pattern template) ...)
。所以符号 <:::>
不允许作为文字列表。
问题是在您的外部宏中省略号跟在 x
之后。这意味着生成的模板在 x
之后也应该有省略号,但实际上没有。如果您将内部宏的 x
重命名为 y
,它应该会按预期工作。
换句话说,你在这里所做的相当于:
(define-syntax foo
(syntax-rules ()
((_ x ...)
(display x))))
这也是不允许的。如果模式中的 x
带有省略号,则在其后的模板中使用 x
时也必须使用这些省略号。
如果您将其设置为 (x y ...)
,它会起作用的原因是模板根本不会消耗 y
(及其省略号)。
您的宏有几个问题。
重用内部宏模板中的词法宏绑定。 x
将在结果中扩展,因此 let-syntax
中的 (_ x)
将被尝试替换,但是由于 x
模板有省略号,因此预计位置 x
被插入在某处有省略号。我认为您的意思不是相同的绑定,因此用任何其他符号替换它都会修复它。例如。 single
使用 let-syntax
意味着你不能有使用相同语法规则的扩展,但在第二个模式中你打印第一个元素然后这样做。将其替换为 letrec-syntax
即可解决此问题。
模式 x ...
匹配 零个或多个 元素。因此 (foo)
匹配模式,但是 bar
没有兼容的模板。添加一个模式来捕捉无操作数的情况可以解决这个问题。
Racket 不支持使用 SRFI-46。您根本不能指望开箱即用地支持它,因此您需要检查每个实现。在 Racket 中,您可以使用 (... ...)
作为替代。这与 R6RS / R7RS 相同。
考虑到这些,我最终得到了这个。在 Racket 中运行良好:
(define-syntax foo
(syntax-rules (:c)
((_) (begin)) ; or you may signal an error
((_ x...)
(letrec-syntax ((bar (syntax-rules (:c)
((_ single)
(print single))
((_ first rest (... ...))
(begin
(display first)
(display " ")
(bar rest (... ...)))))))
(bar x ...)))))
虽然我不知道你的例子有多简化,但可以用这个代替:
(define-syntax foo
(syntax-rules ()
((_ x ...)
(begin
(begin
(display x)
(display " "))
...))))
我正在尝试创建一个简单的嵌套宏。它在我的 Scheme 实现中有效,但在 Guile 和 Racket 中无法 运行。
(define-syntax foo
(syntax-rules (:c)
((_ x ...)
(let-syntax ((bar (syntax-rules ::: (:c)
((_ x)
(print x))
((_ a b :::)
(begin
(display a)
(display " ")
(bar b :::))))))
(bar x ...)))))
- 诡计投掷:
syntax: missing ellipsis
- 球拍投掷:
missing ellipsis with pattern variable in template
我也试过 运行 在 Gambit 中,但那个只是抛出:
Unbound variable: define-syntax
我猜你需要使用库才能使用基本方案。
在 Checken Scheme 中,更新省略号后:
(define-syntax foo
(syntax-rules (:c)
((_ x ...)
(let-syntax ((bar (syntax-rules <:::> (:c)
((_ x)
(print x))
((_ a b <:::>)
(begin
(display a)
(display " ")
(bar b <:::>))))))
(bar x ...)))))
投掷:
template dimension error (too few ellipses?): x
这个宏有什么问题?为什么会抛出错误?
编辑:
看来这个模式是无效的:
(_ x ...)
但这是
(_ x y ...)
这是在某处指定的吗?为什么第一个语法无效?
为了完整起见,这段代码可以编译,但为什么第一个没有?
(define-syntax foo
(syntax-rules ()
((_ x y ...)
(let-syntax ((bar (syntax-rules <:::> ()
((_ x)
(print x))
((_ a b <:::>)
(begin
(display a)
(display " ")
(bar b <:::>))))))
(bar x y ...)))))
但是当尝试使用 foo
宏时它不起作用。它抛出:
unbound variable: bar
即使使用 letrec-syntax
.
外部语法规则中的此模式 (_ x ...)
会将模式变量 x 绑定到匹配列表中。这意味着,当 x
出现在模板中时,它后面必须(不一定直接)跟一个省略号。
这就是您从 Guile 和 Racket 中得到错误的原因。
现在考虑外部宏 (foo) 引入内部宏 (bar) 的情况,其定义包含省略号。当扩展器看到...
是属于外宏定义还是属于内宏定义?
使用的约定(至少是 Racket 和所有语法规则的 psyntax 派生实现)是 ...
属于外层。
为了产生“内部省略号”,需要“引用”。所以生成一个内部省略号,写成(... ...)
.
在实践中这可能很烦人,所以我经常将内部定义包装在
(with-syntax ((ooo (... ...))
code using ooo as an inner ellipsis here)
据我所知,您示例中的 (syntax-rules <:::> () etc)
是非标准的,因为语法是 (syntax-rules literals (pattern template) ...)
。所以符号 <:::>
不允许作为文字列表。
问题是在您的外部宏中省略号跟在 x
之后。这意味着生成的模板在 x
之后也应该有省略号,但实际上没有。如果您将内部宏的 x
重命名为 y
,它应该会按预期工作。
换句话说,你在这里所做的相当于:
(define-syntax foo
(syntax-rules ()
((_ x ...)
(display x))))
这也是不允许的。如果模式中的 x
带有省略号,则在其后的模板中使用 x
时也必须使用这些省略号。
如果您将其设置为 (x y ...)
,它会起作用的原因是模板根本不会消耗 y
(及其省略号)。
您的宏有几个问题。
重用内部宏模板中的词法宏绑定。
x
将在结果中扩展,因此let-syntax
中的(_ x)
将被尝试替换,但是由于x
模板有省略号,因此预计位置x
被插入在某处有省略号。我认为您的意思不是相同的绑定,因此用任何其他符号替换它都会修复它。例如。single
使用
let-syntax
意味着你不能有使用相同语法规则的扩展,但在第二个模式中你打印第一个元素然后这样做。将其替换为letrec-syntax
即可解决此问题。模式
x ...
匹配 零个或多个 元素。因此(foo)
匹配模式,但是bar
没有兼容的模板。添加一个模式来捕捉无操作数的情况可以解决这个问题。Racket 不支持使用 SRFI-46。您根本不能指望开箱即用地支持它,因此您需要检查每个实现。在 Racket 中,您可以使用
(... ...)
作为替代。这与 R6RS / R7RS 相同。
考虑到这些,我最终得到了这个。在 Racket 中运行良好:
(define-syntax foo
(syntax-rules (:c)
((_) (begin)) ; or you may signal an error
((_ x...)
(letrec-syntax ((bar (syntax-rules (:c)
((_ single)
(print single))
((_ first rest (... ...))
(begin
(display first)
(display " ")
(bar rest (... ...)))))))
(bar x ...)))))
虽然我不知道你的例子有多简化,但可以用这个代替:
(define-syntax foo
(syntax-rules ()
((_ x ...)
(begin
(begin
(display x)
(display " "))
...))))