racket-使用模式匹配过程定义语法类

racket-使用模式匹配过程定义语法类,racket,Racket,我试图定义语法类来匹配一个参数,这个参数是过程 我知道如何匹配标识符、表达式和其他语法类 这是我的样本: (define-syntax-class model-property #:description "a model property" #:attributes (name datatype guard) (pattern name:id #:with datatype #`null #:with guard #'

我试图定义语法类来匹配一个参数,这个参数是过程

我知道如何匹配标识符、表达式和其他语法类

这是我的样本:

(define-syntax-class model-property
    #:description "a model property"
    #:attributes (name datatype guard)
    (pattern name:id
             #:with datatype #`null
             #:with guard #'(lambda (value) value)
             )
    (pattern [name:id #:datatype [datatype:id #:not-null] #:guard guard:expr])
    )
我想用类似于
:guard-guard:procedure
的内容替换
:guard-guard:expr

我尝试过

(define-syntax-class model-property-guard
 #:description "a property guard"
(pattern guard:expr
         #:fail-when (procedure? #'guard)
         "property guard should be procedure."))

可能吗?如何执行?

宏在程序执行之前的编译时运行。在编译时,您无法知道表达式将生成哪种类型的值,因为信息根本不存在。(从理论上讲,您可以使用静态类型系统在语言中检查这样的内容,但是,
#lang racket
是动态类型的。)

您可以做的一件事是将约定放在表达式上,以便在约定不匹配时引发运行时错误。为此目的,提供了一个。您可以这样使用它:

(begin-for-syntax
  (define-syntax-class model-property-guard
    #:description "a property guard"
    (pattern (~var guard (expr/c #'procedure?))
             #:with c #'guard.c)))

(define-syntax (m stx)
  (syntax-parse stx
    [(_ guard:model-property-guard)
     #'guard.c]))
使用上述定义,写入
(m add1)
将成功生成
#
,而写入
(m add1)
将在运行时失败并违反合同:

m: contract violation
  expected: procedure?
  given: 1
  in: procedure?
请注意,扩展必须在扩展中使用
guard.c
c
属性包含一个修改过的表达式,该表达式将契约附加到值,直接使用
guard
只会将表达式传递给unchanged,而不附加契约

有关正在运行的
expr/c
的更多示例,请参阅