You wrote your module. You added contracts. You put them into the interface
+You wrote your module. You added contracts. You put them into the interface
so that client programmers have all the information from interfaces. It's a
piece of art:
-
-+expected ??>, given: -10")) -Clearly, @scheme[bank-client] is a module that uses @scheme[myaccount] -but what are the '?' doing there? Wouldn't it be nice if we had a name for this -class of data much like we have string, number, and so on? +Clearly, @scheme[bank-client] is a module that uses +@scheme[myaccount] but what are the @tt{?}s doing there? +Wouldn't it be nice if we had a name for this class of data +much like we have string, number, and so on? --bank-client broke the contract (-> ??? any) +@(make-element "schemeerror" +'("bank-client broke the contract (-> ??? any) it had with myaccount on deposit; -expected <???>, given: -10 --
For this situation, PLT Scheme provides "flat named contracts". The use of
+For this situation, PLT Scheme provides "flat named contracts". The use of
"contract" shows that contracts are first-class values. The "flat" means that
the collection of data is a subset of the built-in atomic classes of data; they
are described by a predicate that consumes all Scheme values and produces a
boolean. The "named" part says what we want to do: name the contract so that
error messages become intelligible:
-
-+expected-bank-client broke the contract (-> amount any) +@(make-element "schemeerror" +'("bank-client broke the contract (-> amount any) it had with myaccount on deposit; -expected <amount>, given: -10 --
Here is an excerpt from an imaginary (pardon the pun) numerics module:
+@question[#:tag "arrow-d"]{Can a contract specify that the result depends on the arguments?}
-
In this particular case, the argument of @scheme[sqrt.v1] is greater +In this particular case, the argument of @scheme[sqrt.v1] is greater or equal to 1. Hence a very basic correctness check is that the result is -smaller than the argument. [Naturally, if this function is critical, one -could strengthen this check with additional clauses.] +smaller than the argument. (Naturally, if this function is critical, one +could strengthen this check with additional clauses.) -
In general, a dependent function contract checks the argument, then -applies the function in the range position to the argument, and uses the -result of this application (usually a closure) as the range check. +In general, a dependent function contract looks just like +the more general @scheme[->*] contract, but with names added +that can be used elsewhere in the contract. -
Let's look at a second example to see how this closure creating business
-works so well here. Take a look at the following module, which exports
-(among other things) a @scheme[deposit] function for a bank
-account. Whether the programmer implements this bank account imperatively
-or functionally, the balance of the account should increase when a customer
-deposits money:
-
-
-
The module implements the creation of accounts, balance checks, account -deposits, and many other functions presumably. In principle, the -@scheme[deposit] function consumes an account and an amount, adds the -amount to the account, and returns the (possibly modified) account. - -
To ensure the increase in the account's balance, the contract is a -dependent contract. The function on the right of the @scheme[->d] -contract combinator consumes the two argument values: an account and an -amount. It then returns a function that checks @scheme[deposit]'s -result. In this case, it checks whether the result is an account and -whether @scheme[balance0] is smaller than the account's balance. Note -that @scheme[balance0] is the value that @scheme[balance] extracted -from the given account before the range-checking function was -produced. - -
Exactly! - -
The contract for @scheme[sqrt.v1] suggests that curried versions of -the numeric comparison operators would come in handy for defining contracts -and combining them with contract combinators such as @scheme[->d]. - -
Here is a revision of the
-@scheme[numerics] module that exploits these special contract
-combinators:
-
-
Thus in the above example, the contract for @scheme[sqrt.v2] makes -sure that its argument is greater or equal to 1.0 and that its result is -less than or equal to its argument. - -
Yes, there are many other contract combinators such as @scheme[<=/c] +Yes, there are many other contract combinators such as @scheme[<=/c] and @scheme[>=/c], and it pays off to look them up in the contract -report section (of the mzlib manual). They simplify contracts tremendously +section of the reference manual. They simplify contracts tremendously and make them more accessible to potential clients. -