Racket:在合同中使用的自定义谓词
Racket: Custom predicate to use within contract
我正在用 Racket 编写小型宠物项目并使用 Gregor 库来处理日期。
我有接受两个日期的函数(来自 Gregor,不是标准库),我想为其添加合同。合同应规定第一个参数的日期必须比第二个参数的日期 less/earlier。
在 Gregor 中我们可以通过使用 (date<=? x y) 或类似的谓词来实现它,但我不明白如何将它与契约结合起来。
(contract-out
[process-dates (->i ([x date?]
[y (x) (and/c date?
(date>=? x))])])
将不起作用,并且没有开箱即用的 date>=?/c
谓词。
所以我想我需要自己写这样的谓词,所以我想知道如何去做。我查看了 Racket 资源,发现标准功能 quite complicated 可以重现。
有没有更简单的方法来实现我想要的?
最简单的方法是使用lambda
:
(->i ([x date?]
[y (x) (and/c date? (lambda (y) (date>=? y x)))])
[_ any/c])
一个缺点是,如果违反约定,错误消息将包含一个 ???
来代替 lambda 表达式。如果你想让它在那里打印更有意义的东西,你可以这样做:
(define (date>=/c x)
(flat-named-contract
`(date>=/c ,x)
(lambda (y) (date>=? y x))))
....
(->i ([x date?]
[y (x) (and/c date? (date>=/c x))])
[_ any/c])
如果您想更好地控制错误消息,可以尝试使用 flat-contract-with-explanation
。
虽然 Ryan 的回答很好,但我发现可以使用前提条件以下列方式解决此问题:
(->i ([x date?]
[y date?])
#:pre (x y) (date<=? x y)
;; ...
)
我正在用 Racket 编写小型宠物项目并使用 Gregor 库来处理日期。
我有接受两个日期的函数(来自 Gregor,不是标准库),我想为其添加合同。合同应规定第一个参数的日期必须比第二个参数的日期 less/earlier。
在 Gregor 中我们可以通过使用 (date<=? x y) 或类似的谓词来实现它,但我不明白如何将它与契约结合起来。
(contract-out
[process-dates (->i ([x date?]
[y (x) (and/c date?
(date>=? x))])])
将不起作用,并且没有开箱即用的 date>=?/c
谓词。
所以我想我需要自己写这样的谓词,所以我想知道如何去做。我查看了 Racket 资源,发现标准功能 quite complicated 可以重现。
有没有更简单的方法来实现我想要的?
最简单的方法是使用lambda
:
(->i ([x date?]
[y (x) (and/c date? (lambda (y) (date>=? y x)))])
[_ any/c])
一个缺点是,如果违反约定,错误消息将包含一个 ???
来代替 lambda 表达式。如果你想让它在那里打印更有意义的东西,你可以这样做:
(define (date>=/c x)
(flat-named-contract
`(date>=/c ,x)
(lambda (y) (date>=? y x))))
....
(->i ([x date?]
[y (x) (and/c date? (date>=/c x))])
[_ any/c])
如果您想更好地控制错误消息,可以尝试使用 flat-contract-with-explanation
。
虽然 Ryan 的回答很好,但我发现可以使用前提条件以下列方式解决此问题:
(->i ([x date?]
[y date?])
#:pre (x y) (date<=? x y)
;; ...
)