球拍:宏扩展内部匹配模式
racket: macro expand inside match pattern
有什么方法可以检测宏是否在模式匹配中展开?
这是我想编写的示例宏,但它在 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
您要找的是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
是的。不要使用使用 define-syntax
创建的普通语法转换器,而是使用 define-match-expander
to create a macro that can 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
结合以实现上述双参数功能,但它也可以保持状态,并且可以与 other 结构类型属性配对,例如 prop:rename-transformer
允许相同的标识符在许多不同的上下文中起作用。
有什么方法可以检测宏是否在模式匹配中展开?
这是我想编写的示例宏,但它在 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
您要找的是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
是的。不要使用使用 define-syntax
创建的普通语法转换器,而是使用 define-match-expander
to create a macro that can 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
结合以实现上述双参数功能,但它也可以保持状态,并且可以与 other 结构类型属性配对,例如 prop:rename-transformer
允许相同的标识符在许多不同的上下文中起作用。