Racket 宏定义给定重复模式的函数 [英] Racket macro to define functions given a repeated pattern
问题描述
这个问题很难解释,因为我需要收集我的想法,所以请耐心等待.出于说明目的,我已经能够将问题简化为一个最小的示例.这个例子对于这有什么用没有任何意义,但我离题了.假设我想扩展球拍语言来编写如下所示的内容:
The problem is quite difficult to explain because I need to collect my thoughts, so bear with me. I've been able to reduce the problem to a minimal example for illustrative purposes. The example will not make any sense as to what this would be useful for, but I digress. Say I want to extend the racket language to write things that look like this:
(define-something
(['a] 'whatever)
(['b 'c] 'whatever2))
方括号之间是一个或多个符号的序列,后面是一系列球拍表达式(whatever
,对问题陈述不重要)
Between the square brackets is a sequence of one or more symbols, followed by a sequence of racket expressions (the whatever
's, which are not important for the problem statement)
该示例将匹配一个看起来像这样的宏:
The example would match a macro that looks something like this:
(define-syntax (define-something stx)
(syntax-case stx ()
[(_ ([symb ...] body ...) ...)
#'()]))
实际上在这里我们匹配 0 个或多个符号,但我们可以假设总是至少有一个.
Actually here we match 0 or more symbols, but we can assume there is always going to be at least one.
在宏的主体中,我想使用连接的符号作为标识符生成函数定义.因此,对于我们愚蠢的示例,宏将扩展为:
In the macro's body I want to generate function definitions using the concatenated symbols as the identifier. So for our silly example the macro would expand to something like:
(define (a) 'whatever)
(define (bc) 'whatever2)
我发现了一个类似的问题,其中海报使用预定义的字符串列表生成函数,但我对宏不是那么流利,所以我无法翻译概念来解决我的问题.我想也许我可以尝试生成一个类似的列表(通过连接符号)并应用它们的策略,但我一直对宏定义中的所有省略号感到困惑.我也对他们在 with-syntax
中使用省略号感到有些困惑.
I have found a similar question where the poster generates functions using a pre-defined list of strings, but I am not that fluent with macro's so I have not been able to translate the concepts to solve my problem. I thought perhaps I could try generating a similar list (by concatenating the symbols) and applying their tactic, but I've been getting way too confused with all the ellipses in my macro definition. I'm also a bit confused about their use of an ellipsis in with-syntax
.
推荐答案
使用 with-syntax
和 syntax-case
可以解决这个问题,但最简单的方法是这是通过使用 syntax-parse
的语法类来实现的.通过定义解析符号列表并生成单个连接标识符的语法类,您可以将符号解析从宏体中提取出来:
It’s possible to solve this with with-syntax
and syntax-case
, but the easiest way to do this is by using syntax-parse
’s syntax classes. By defining a syntax class that parses a list of symbols and produces a single concatenated identifier, you can lift the symbol parsing out of the macro body:
(require (for-syntax syntax/parse
racket/string))
(begin-for-syntax
(define-syntax-class sym-list
#:attributes [concatenated-id]
(pattern (~and stx (sym:id ...))
#:attr concatenated-id
(let* ([syms (syntax->datum #'(sym ...))]
[strs (map symbol->string syms)]
[str (string-append* strs)]
[sym (string->symbol str)])
(datum->syntax #'stx sym #'stx #'stx)))))
现在您可以非常轻松地定义宏:
Now you can define your macro pretty easily:
(define-syntax (define-something stx)
(syntax-parse stx
[(_ (syms:sym-list body ...) ...)
#'(begin
(define (syms.concatenated-id) body ...)
...)]))
请注意,这在 name 子句中使用了不带引号的符号,因此它的工作方式如下:
Note that this uses unquoted symbols in the name clause, so it would work like this:
(define-something
([a] 'whatever)
([b c] 'whatever2))
名称不能是计算为符号的表达式,因为需要在编译时知道信息才能用于宏扩展.由于您在评论中提到这是针对类似 FRP 的系统,因此您的信号图需要是静态的,例如 Elm 的.如果您想要构建动态信号图的能力,您将需要比宏更复杂的策略,因为该信息需要在运行时解析.
The names can’t be expressions that evaluate to symbols because the information needs to be known at compile-time to be available to macro expansion. Since you mentioned in a comment that this is for an FRP-like system, your signal graph will need to be static, like Elm’s is for example. If you want the ability to construct a dynamic signal graph, you’ll need a more complex strategy than macros since that information will need to be resolved at runtime.
这篇关于Racket 宏定义给定重复模式的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!