【问题标题】:Racket macro to define functions given a repeated pattern球拍宏定义给定重复模式的功能
【发布时间】:2016-01-13 20:35:49
【问题描述】:

这个问题很难解释,因为我需要收集我的想法,所以请耐心等待。出于说明目的,我已经能够将问题简化为一个最小的示例。这个例子对于这将是有用的没有任何意义,但我离题了。假设我想扩展球拍语言以编写如下所示的内容:

(define-something
  (['a] 'whatever)
  (['b 'c] 'whatever2))

方括号之间是一个或多个符号的序列,后跟一系列球拍表达式(whatever's,这对于问题陈述并不重要)

该示例将匹配如下所示的宏:

(define-syntax (define-something stx)
  (syntax-case stx ()
    [(_  ([symb ...] body ...) ...)
     #'()]))

实际上我们在这里匹配了 0 个或多个符号,但我们可以假设总会有至少一个。

在宏的主体中,我想使用连接符号作为标识符来生成函数定义。因此,对于我们愚蠢的示例,宏将扩展为:

(define (a) 'whatever)
(define (bc) 'whatever2)

我找到了一个similar question,发帖人使用预定义的字符串列表生成函数,但我对宏不是很流利,所以我无法翻译这些概念来解决我的问题。我想也许我可以尝试生成一个类似的列表(通过连接符号)并应用他们的策略,但我对我的宏定义中的所有省略号感到太困惑了。我也对他们在with-syntax 中使用省略号感到有些困惑。

【问题讨论】:

  • 这只是一个帮助学习宏的练习,还是有什么目的?它在所述形式中似乎不是非常有用。
  • 我真正想做的是在反应式编程的背景下。这些符号实际上是反应信号(我可能可以将其简化为每个信号的唯一符号)。当一个信号发生变化时(例如信号'a'),我执行 body 'whatever'。当两个信号“a”和“c”都发生变化时(并且为“a”和“c”定义了一个主体)我想执行“whatever2”。一旦方法被生成为球拍类的一部分,实际上很容易使用动态发送(它接受符号方法名称)来调用它们。抱歉,这需要更多解释,但我仍在尝试自己。
  • 我想要生成方法的另一个(主要)原因是我可以非常轻松地向方法添加参数。然后可以在方法的生成主体中使用这些参数,就好像它们只是“存在”一样,我不必担心以另一种方式引入这些“魔术变量”。如果您想要更多信息,或者包含比推文更多字符的合理解释,我很乐意提供!

标签: scheme racket


【解决方案1】:

使用with-syntaxsyntax-case 可以解决这个问题,但最简单的方法是使用syntax-parse 的语法类。通过定义解析符号列表并生成单个连接标识符的语法类,您可以将符号解析从宏体中提取出来:

(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)))))

现在你可以很容易地定义你的宏了:

(define-syntax (define-something stx)
  (syntax-parse stx
    [(_ (syms:sym-list body ...) ...)
     #'(begin
         (define (syms.concatenated-id) body ...)
         ...)]))

请注意,这在 name 子句中使用了不带引号的符号,因此它的工作方式如下:

(define-something
  ([a] 'whatever)
  ([b c] 'whatever2))

名称不能是评估为符号的表达式,因为需要在编译时知道信息才能用于宏扩展。由于您在评论中提到这是针对类似 FRP 的系统,因此您的信号图需要是静态的,例如 Elm 的。如果您希望能够构建动态信号图,则需要比宏更复杂的策略,因为这些信息需要在运行时解析。

【讨论】:

  • 是的,信号图是静态的 :) 我将尝试一下语法解析。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-13
  • 1970-01-01
  • 2020-03-18
  • 2017-02-03
相关资源
最近更新 更多