【问题标题】:racket: macro expand inside match pattern球拍:宏在比赛模式内展开
【发布时间】:2016-06-06 04:40:40
【问题描述】:

有什么方法可以检测宏是否在模式匹配中扩展?

这是我想编写的示例宏,但它在 match-define 内失败:

#lang racket/base
(require racket/match (for-syntax racket/base syntax/parse))

(struct point (x y))

(define-syntax (friendly-point stx)
  (syntax-parse stx
   [(_ arg* ...)
    #'(begin (printf "Now making a point\n") (point arg* ...))]
   [_ #'(begin (printf "Hello point\n") point)]))

(define p (friendly-point 1 2))
 ;; Prints "Now making a point"

(match-define (friendly-point x y) p)
;; ERROR

【问题讨论】:

    标签: macros racket


    【解决方案1】:

    是的。不要使用使用define-syntax 创建的普通语法转换器,而是使用define-match-expander 创建一个可以cooperate with match 的宏。

    (require (for-syntax syntax/parse))
    
    (define-match-expander positive
      (syntax-parser
        [(_ n)
         #'(? positive? n)]))
    
    (match 3
      [(positive n) (~a n " is positive")])
    ; => "3 is positive"
    

    define-match-expander 形式很灵活:它可用于创建只能match 内部使用的宏,但它也可用于创建扩展方式不同的宏,具体取决于如何通过提供两个转换器函数来使用它们,每个上下文一个。这允许您拥有“上下文相关”的标识符,它们既可以作为函数 也可以作为匹配扩展器使用

    (require (for-syntax syntax/parse)
             (prefix-in base: racket/base))
    
    (define-match-expander syntax
      (syntax-parser
        [(_ x)
         #'(? syntax? (app syntax->datum x))])
      (make-rename-transformer #'base:syntax))
    
    (match (syntax (1 2 3))
      [(syntax n) (~a n " is a syntax list")])
    

    如果您需要更多灵活性,您可以完全放弃define-match-expander,并使用prop:match-expander 结构类型属性定义一个自定义结构。这可以与prop:procedure结合来实现上面描述的双参数功能,但它也可以保持状态,并且可以与prop:rename-transformer其他结构类型属性配对以允许相同的标识符在许多不同的上下文中起作用。

    【讨论】:

      【解决方案2】:

      您正在寻找的是define-match-expander。它允许您创建一个在模式匹配上下文中扩展的宏。 (另外,因为它需要两个 thunk,所以你可以有一个变体,当不在匹配的上下文中时也可以使用它。接下来,我应该指出

      接下来,您可以在define-match-expander 的模板中添加打印副作用,但您可以在宏本身中添加。 (请注意,如果您的模块已经扩展,则不会发生副作用。这是更详细的解释in this paper

      因此,使用匹配扩展器,包括在匹配之外使用的第二个函数,您将获得以下代码:

      #lang racket/base
      
      (require racket/match (for-syntax racket/base syntax/parse))
      
      (struct point (x y))
      
      (define-match-expander friendly-point
        (lambda (stx)
          (syntax-parse stx
            [(_ arg* ...)
             (printf "Now matching a point\n")
             #'(point arg* ...)]
            [_ #'point]))
        (lambda (stx)
          (syntax-parse stx
            [(_ args* ...)
             #'(begin (printf "Now making a point\n") (point args* ...))])))
      
      (define p (friendly-point 1 2))
       ;; Prints "Now making a point"
      
      (match-define (friendly-point x y) p)
      ;; Works fine now
      

      【讨论】:

        猜你喜欢
        • 2016-08-07
        • 1970-01-01
        • 1970-01-01
        • 2020-11-01
        • 2016-04-26
        • 1970-01-01
        • 2022-01-16
        • 2012-04-09
        相关资源
        最近更新 更多