球拍-具有模式匹配过程的定义语法类

Jar*_*aro 3 racket

我正在尝试定义与过程参数相匹配的语法类。

我知道如何匹配标识符,表达式,另一个语法类。

这是我的示例:

(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])
    )
Run Code Online (Sandbox Code Playgroud)

我想#:guard guard:expr用类似的东西代替#:guard guard:procedure

我尝试过

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

可能吗?怎么样?

Ale*_*ing 5

宏在程序执行之前在编译时运行。在编译时,您不知道表达式将产生什么样的值-信息根本不存在。(从理论上讲,您可以使用具有静态类型系统的语言来检查此类内容,但#lang racket可以动态键入。)

可以做的一件事是将契约放在表达式上,以便在契约不匹配时引发运行时错误。该expr/c语法类被用于此目的。您可以这样使用它:

(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]))
Run Code Online (Sandbox Code Playgroud)

使用以上定义,写入(m add1)将成功产生#<procedure:add1>,而写入(m 1)将在运行时因违反合同而失败:

m: contract violation
  expected: procedure?
  given: 1
  in: procedure?
Run Code Online (Sandbox Code Playgroud)

注意扩展必须guard.c在扩展中使用!该c属性包含一个修改后的表达式,该表达式将合同附加到该值,并且guard直接使用该表达式将仅通过不变的表达式,而无需附加合同。

有关expr/c实际操作的更多示例,请参见宏子表达式上的协定