Mzlib's contract.ss library defines new forms of expression that specify contracts and new forms of expression that attach contracts to values.
This section describes two classes of contracts: contracts for flat values (described in section 10.1) and contracts for functions (described in section 10.2).
In addition, this section describes two forms for establishing a contract on a value (described in section 10.3).
A contract for a flat value can be a predicate that accepts the value and returns a boolean indicating if the contract holds.
(flat-named-contract
type-name predicate
)
PROCEDURE
For better error reporting, a flat
contract can be constructed with
flat-named-contract
, a procedure that accepts two
arguments. The first argument must be a string that
describes the type that the predicate checks for. The second
argument is the predicate itself.
(flat-named-contract-type-name
flat-named-contract
)
PROCEDURE
Extracts the type name from a flat-named-contract
.
(flat-named-contract-predicate
flat-named-contract
)
PROCEDURE
Extracts the predicate from a flat-named-contract
.
In addition, this library provides many helper functions for constructing contracts.
(union
contract ...
)
PROCEDURE
union
accepts any number of
predicates and at most one function contract and returns
a contract that corresponds to the union of them all.
and/f
accepts a list of predicates and
returns a predicate that is the conjunction of those
predicates.
(or/f
predicate ...
)
PROCEDURE
or/f
accepts a list of predicates and
returns a predicate that is the disjuction of those
predicates.
>=/c
accepts a number and
returns a predicate that requires the input to be a number
and greater than or equal to the original input.
<=/c
accepts a number and
returns a predicate that requires the input to be a number
and less than or equal to the original input.
>/c
accepts a number and
returns a predicate that requires the input to be a number
and greater than the original input.
</c
accepts a number and
returns a predicate that requires the input to be a number
and less than the original input.
natural-number?
returns
#t
if the input is a natural number and
#f
otherwise.
false?
returns true if the input
is #f
and #t
otherwise.
printable?
returns #t
for any value that can be written out and read back in.
any?
always returns #t
.
(symbols
symbol ...
)
PROCEDURE
symbols
accepts any number of symbols and returns a
predicate that checks for those symbols.
(is-a?/c
class-or-interface
)
PROCEDURE
is-a?/c
accepts a class or
interface and returns a predicate that checks if objects are
subclasses of the class or implement the interface.
(implementation?/c
interface
)
PROCEDURE
implementation?/c
accepts an interface and returns a predicate that checks if
classes are implement the given interface.
subclass?/c
accepts a class
and returns a predicate that checks if classes are
subclasses of the original class.
(listof
flat-contract
)
FLAT-CONTRACT
listof
accepts a flat contract and
returns a predicate that checks for lists whose elements
match the original predicate.
(vectorof
flat-contract
)
FLAT-CONTRACT
vectorof
accepts a flat contract and
returns a predicate that checks for vectors whose elements
match the original predicate.
(vector/p
flat-contract ...
)
FLAT-CONTRACT
vector/p
accepts any number of flat contract and
returns a predicate that checks for vectors. The number of
elements in the vector must match the number of arguments
supplied to vector/p
and the elements of the
vector must match the corresponding flat contract.
(box/p
flat-contract
)
FLAT-CONTRACT
box/p
accepts a flat contract
and returns a flat contract that checks for boxes whose
contents match box/p
's argument.
(cons/p
flat-contract flat-contract
)
FLAT-CONTRACT
cons/p
accepts two predicates
and returns a predicate that checks for cons cells whose
car and cdr correspond to cons/p
's two arguments.
(list/p
flat-contract ...
)
PROCEDURE
list/p
accepts an arbitrary
number of arguments and returns a predicate that checks for
lists whose length is the same as the number of arguments to
list/p
and whose elements match those arguments.
mixin-contract
is a
contract that matches mixins. It is a function
contract. It guarantees that the input to the function is
a class and the result of the function is a subclass of
the input.
(make-mixin-contract
class-or-interface ...
)
PROCEDURE
make-mixin-contract
is a function that constructs mixins contracts. It accepts
any number of classes and interfaces and returns a
function contract. The function contract guarantees that
the input to the function implements the interfaces and is
derived from the classes and that the result of the
function is a subclass of the input.
This section describes the contract constructors for function contracts. This is their shape:
contract-expr ::== | (case-> arrow-contract-expr ...) | arrow-contract-expr arrow-contract-expr ::== | (-> expr ... expr) | (-> expr ... any) | (->* (expr ...) expr (expr ...)) | (->* (expr ...) (expr ...)) | (->d expr ... expr) | (->*d (expr ...) expr) | (->*d (expr ...) expr expr) | (opt-> (expr ...) (expr ...) expr) | (opt->* (expr ...) (expr ...) (expr ...))
where expr
is any Scheme expression.
The ->
contract is for functions that accept a
fixed number of arguments and return a single result. The
last argument to ->
is the contract on the result
of the function and the other arguments are the contracts on
the arguments to the function. Each of the arguments to
->
must be another contract expression or a
predicate. For example, this expression:
(integer? boolean? . -> . integer?)
is a contract on functions of two arguments. The first must
be an integer and the second a boolean and the function must
return an integer. (This example uses
MzScheme's infix notation
so that the ->
appears in a suggestive place; see section 14.3 in PLT MzScheme: Language Manual).
If any
is used as the last argument to ->
,
no contract checking is performed on the result of the
function, and tail-recursion is preserved.
(->*
(expr ...) (expr ...)
)
SYNTAX
(->*
(expr ...) expr (expr ...)
)
SYNTAX
The ->*
expression is for functions that return
multiple results and/or have rest arguments. If two
arguments are supplied, the first is the contracts on the
arguments to the function and the second is the contract on
the results of the function. If three arguments are
supplied, the first argument contains the contracts on the
arguments to the function (excluding the rest argument), the
second contains the contract on the rest argument to the
function and the final argument is the contracts on the
results of the function.
(->*d
(expr ...) expr)
)
SYNTAX
(->*d
(expr ...) expr expr
)
SYNTAX
The ->d
and ->*d
contract constructors are
like their d-less counterparts, except that the
result portion is a function that accepts the original
arguments to the function and returns the range contracts.
The range contract function for ->*d
must return
multiple values: one for each result of the original
function.
As an example, this is the contract for
:
sqrt
(number?
. ->d . (lambda (in) (lambda (out) (and (number?
out) (abs (- (* out out) in) 0.01)))))
It says that the input must be a number and that the
difference between the square of the result and the original
number is less than 0.01
.
(case->
arrow-contract-expr ...
)
CONTRACT-CASE->
The case->
expression constructs a contract for
case-lambda function. It's arguments must all be function
contracts, built by one of ->
, ->d
,
->*
, or ->*d
.
(opt->
(req-contracts ...) (opt-contracts ...) res-contract)
)
SYNTAX
(opt->*
(req-contracts ...) (opt-contracts ...) (res-contracts ...)
)
SYNTAX
The opt->
expression constructs a contract for an
opt-lambda
function. The first arguments are the
required parameters, the second arguments are the optional
parameters and the final argument is the result. Each
opt->
expression expands into case->
.
The opt->*
expression constructs a contract for an
opt-lambda
function. The only difference between
opt->
and opt->*
is that multiple return
values are permitted with opt->*
and they are
specified in the last clause of an opt->*
expression.
(provide/contract
(id expr) ...
)
SYNTAX
There are two special forms that add contract
specifications, provide/contract
and
contract
. A provide/contract
form
has this shape:
(provide/contract (id expr) ...)
and can only appear at the top-level of a
module (see section 5 in PLT MzScheme: Language Manual). As with
provide
, each identifier is provided from the
module. In addition, clients of the module must live up to
the contract specified by expr
.
(contract
contract-expr to-protect-expr positive-blame negative-blame
)
SYNTAX
(contract
contract-expr to-protect-expr positive-blame negative-blame contract-source
)
SYNTAX
The contract
special form is the primitive
mechanism for attaching a contract to a value. Its purpose
is as a target for the expansion of some higher-level
contract specifying form.
The contract
form has this shape:
(contract expr to-protect-expr positive-blame negative-blame contract-source)
The contract
expression adds the contract specified
by the first argument to the value in the second argument.
The result of a contract
expression is the result
of the to-protect-expr
expression, but with the
contract specified by contract-expr
enforced on
to-protect-expr
. The expressions
positive-blame
and negative-blame
must be
symbols indicating how to assign blame for positive and
negative positions of the contract specified by
contract-expr
. Finally, contract-source
,
if specified, indicates where the contract was assumed. It
must be a syntax object specifying the source location of
the location where the contract was assumed. If the syntax
object wraps a symbol, the symbol is used as the name of the
primitive whose contract was assumed. If
absent, it defaults to the source location of the
contract
expression.
The procedure contract?
returns #t
if its
argument was constructed with one of the arrow constructors
described earlier in this section, or if its argument is a
procedure of arity 1
.