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."))
可能吗?如何?
解决方案
宏在程序执行之前在编译时运行。在编译时,您无法知道表达式将产生什么样的值——信息根本不存在。(理论上,您可以在具有静态类型系统的语言中检查这样的事情,但#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
,请参阅宏子表达式上的合同。