代码之家  ›  专栏  ›  技术社区  ›  Jaro

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

  •  2
  • Jaro  · 技术社区  · 8 年前

    我正在努力定义与过程参数匹配的语法类。

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

    这是我的样品:

    (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 回复  |  直到 8 年前
        1
  •  4
  •   Alexis King    8 年前

    宏在编译时运行,在程序执行之前。在编译时,您不能知道表达式将产生哪种类型的值,这些信息根本不存在。(理论上,你可以用静态类型系统在语言中检查这样的东西,但是 #lang racket 是动态类型。)

    有件事你 可以 do是将协定放在表达式上,以便在协定不匹配时引发运行时错误。这个 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.c 在扩张中!这个 c 属性包含将协定附加到值的已修改表达式,并使用 guard 直接通过不变的表达,没有附加合同。

    更多关于 EXPR/C 实际操作中,请参见 Contracts on Macro Sub-expressions .