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

时间:2018-07-02 13:31:55

标签: 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])
    )

我想将#: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."))

有可能吗?怎么样?

1 个答案:

答案 0 :(得分:4)

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

您可以 要做的一件事是在表达式上放置合同,以便在合同不匹配时引发运行时错误。为此提供了expr/c syntax class。您可以这样使用它:

(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)将成功产生#<procedure:add1>,而编写(m 1)将在运行时因违反合同而失败:

m: contract violation
  expected: procedure?
  given: 1
  in: procedure?

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

有关实际使用的expr/c的更多示例,请参见Contracts on Macro Sub-expressions