首页 > 解决方案 > 球拍 - 使用模式匹配过程定义语法类

问题描述

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

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

这是我的样本:

(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."))

可能吗?如何?

标签: racket

解决方案


宏在程序执行之前在编译时运行。在编译时,您无法知道表达式将产生什么样的值——信息根本不存在。(理论上,您可以在具有静态类型系统的语言中检查这样的事情,但#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]))

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

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

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

有关实际操作的更多示例expr/c,请参阅宏子表达式上的合同


推荐阅读