我需要解释为什么这种“外包”不起作用。 它只应返回正值,但仍接受负值。谁能解释?谢谢。
#lang racket
(struct account (balance))
(provide (contract-out
[balance (-> account? number?)]
[deposit (-> account? positive-num? account?)]))
(define new-account (account 0))
(define (positive-num? n)
(cond [(not (number? n)) #f]
[(> n 0) #t]))
(define (balance acc)
(account-balance acc))
(define (deposit acc amt)
(account (+ (account-balance acc) amt)))
(displayln (balance (deposit new-account -10)))
答案 0 :(得分:2)
编写的程序存在两个问题。
首先,您的positive-num?
谓词是错误的。尝试使用负数-您将不会获得#f
的回馈。您的实现将使(positive-num? -10)
产生#<void>
(因为没有cond
子句匹配),它不是#f
,因此是真实的。您可以将positive-num?
的主体重写为简单的(and (number? n) (> n 0))
,这既清楚又正确,但是您也可以完全废弃自定义positive-num?
谓词,而仅使用合同{{1} }。
代码的第二个问题更加微妙。给值赋予合同时,合同会附在合同边界上。只要在合同边界外使用值,合同就会强制执行,但合同边界内不会强制执行。这是因为,在合同范围内,您是直接使用该值,而不是附带合同的值。
使用(and/c real? positive?)
时,合同边界是提供标识符的模块。在模块外部,合同是强制执行的,而在模块内部则不是。因此,由于您的整个程序都在一个模块中,因此合同永远都没有关系。
要查看实际效果,请尝试一个由多个模块组成的程序:
contract-out
由于合同规定的定义已移至单独的子模块中,并且由于对#lang racket
(module bank racket
(provide (contract-out
[balance (-> account? number?)]
[deposit (-> account? (and/c real? positive?) account?)]
[new-account account?]))
(struct account (balance))
(define new-account (account 0))
(define (balance acc)
(account-balance acc))
(define (deposit acc amt)
(account (+ (account-balance acc) amt))))
(require 'bank)
(displayln (balance (deposit new-account -10)))
的调用在该子模块之外,因此上述代码引发了合同违约:
deposit
如果想要要在同一模块中执行的合同,则需要使用一种表格,该表格创建的合同边界比deposit: contract violation
expected: a number strictly greater than 0
given: -10
in: the 2nd argument of
(->
account?
(and/c real? positive?)
account?)
contract from: (anonymous-module bank)
blaming: anonymous-module
(assuming the contract is correct)
at: unsaved-editor:6.13
更细。 define/contract
是一种这样的形式,它在定义本身与定义主体外部的所有内容之间建立了边界:
contract-out
现在,即使用法和定义在同一模块中,也会显示违反合同的情况。
有关合同边界以及为什么要选择另一种形式的更多详细信息,请参见《球拍指南》中的Contracts and Boundaries。