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 three classes of contracts: contracts for flat values (described in section 13.1), contracts for functions (described in section 13.2), and contracts for objects and classes (described in section 13.3).
In addition, this section describes how to establishing a contract on a value (in section 13.4).
A contract for a flat value can be a predicate that accepts the value and returns a boolean indicating if the contract holds.
(flat-contract
predicate
)
FLAT-CONTRACT
Constructs a contract from predicate
.
(flat-named-contract
type-name predicate
)
FLAT-CONTRACT
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.
any?
is a flat contract that accepts any value.
If you are using this predicate as the result portion of a
function contract, consider using any
instead. It
behaves the same, but in that one restrictive context has
better memory performance.
union
accepts any number of
predicates and at most one function contract and returns
a contract that corresponds to the union of them all. If
all of the arguments are predicates or flat contracts, it
returns a flat contract.
and/c
accepts any number of contracts and returns
a contract that checks that all of the argument contracts
hold. If all of the arguments are flat
contracts, and/c
produces a flat contract.
(not/f
flat-contract
)
FLAT-CONTRACT
not/f
accepts a flat contracts (or
a predicate which is implicitly converted to a flat
contracts via flat-contract
) and returns a
flat contract that checks the reverse of the argument.
>=/c
accepts a number and returns a flat contract
that requires the input to be a number and greater than or
equal to the original input.
<=/c
accepts a number and returns a
flat contract that requires the input to be a number and
less than or equal to the original input.
>/c
accepts a number and returns a flat contract
that requires the input to be a number and greater than
the original input.
</c
accepts a number and returns a flat contract
that requires the input to be a number and less than the
original input.
(integer-in
number number
)
FLAT-CONTRACT
integer-in
accepts two numbers and returns a
flat contract that recognizes if integers between the two
inputs, or equal to one of its inputs.
(real-in
number number
)
FLAT-CONTRACT
real-in
accepts two numbers and returns a
flat contract that recognizes real numbers between the two
inputs, or equal to one of its inputs.
natural-number?
is a contract that recognizes
natural numbers (i.e., an integer that is either
positive or zero).
(string/len
number
)
FLAT-CONTRACT
string/len
accepts a number and returns a flat contract
that recognizes strings that have fewer than that number
of characters.
false?
is a flat contract that recognizes #f
.
printable?
is a flat contract that recognizes
values that can be written out and read back in
with
and write
.read
(symbols
symbol
···1)
FLAT-CONTRACT
symbols
accepts any number of symbols and returns a
flat contract that recognizes for those symbols.
(is-a?/c
class-or-interface
)
FLAT-CONTRACT
is-a?/c
accepts a class or
interface and returns a flat contract that recognizes if
objects are subclasses of the class or implement the
interface.
(implementation?/c
interface
)
FLAT-CONTRACT
implementation?/c
accepts an interface and returns a flat contract that
recognizes if classes are implement the given interface.
(subclass?/c
class
)
FLAT-CONTRACT
subclass?/c
accepts a class
and returns a flat-contract that recognizes classes that
are subclasses of the original class.
(listof
flat-contract
)
FLAT-CONTRACT
listof
accepts a flat contract (or a predicate
which is converted to a flat contract) and returns a flat
contract that checks for lists whose elements match the
original flat contract.
(list-immutableof
contract
)
CONTRACT
list-immutableof
accepts a contract (or a predicate
which is converted to a flat contract) and returns a
contract that checks for immutable lists whose elements
match the original contract. In contrast
to listof
, list-immutableof
accepts
arbitrary contracts, not just flat contracts.
Beware, however, that when a value is applied to this
contract, the result will not be
to the
input.eq?
(vectorof
flat-contract
)
FLAT-CONTRACT
vectorof
accepts a flat contract (or a predicate
which is converted to a flat contract
via flat-contract
) and returns a predicate that
checks for vectors whose elements match the original
flat contract.
(vector-immutableof
contract
)
CONTRACT
vector-immutableof
accepts a contract (or a predicate
which is converted to a flat contract) and returns a
contract that checks for immutable lists whose elements
match the original contract. In contrast
to vectorof
, vector-immutableof
accepts
arbitrary contracts, not just flat contracts.
Beware, however, that when a value is applied to this
contract, the result will not be
to the
input.eq?
(vector/p
flat-contract
···)
FLAT-CONTRACT
vector/p
accepts any number of flat contracts (or predicates
which are converted to flat contracts
via flat-contract
) and returns a flat-contract that
recognizes 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 contracts.
(vector-immutable/c
contract
···)
CONTRACT
vector-immutable/c
accepts any number of contracts (or predicates
which are converted to flat contracts
via flat-contract
) and returns a contract that
recognizes vectors. The number of elements in the vector
must match the number of arguments supplied
to vector-immutable/c
and the elements of the
vector must match the corresponding contracts.
In contrast to vector/p
, vector-immutable/c
accepts arbitrary contracts, not just flat contracts.
Beware, however, that when a value is applied to this
contract, the result will not be
to the
input.eq?
(box/p
flat-contract
)
FLAT-CONTRACT
box/p
accepts a flat contract (or predicate that
is converted to a flat contract via flat-contract
)
and returns a flat contract that recognizes for boxes whose
contents match box/p
's argument.
(box-immutable/c
contract
)
CONTRACT
box-immutable/c
accepts any number of contracts (or predicates
which are converted to flat contracts
via flat-contract
) and returns a contract that
recognizes vectors. The number of elements in the vector
must match the number of arguments supplied
to box-immutable/c
and the elements of the
vector must match the corresponding contracts.
In contrast to box/p
, box-immutable/c
accepts arbitrary contracts, not just flat contracts.
Beware, however, that when a value is applied to this
contract, the result will not be
to the
input.eq?
(cons/p
flat-contract flat-contract
)
FLAT-CONTRACT
cons/p
accepts two flat contracts (or predicates
that are converted to flat contracts
via flat-contract
) and returns a flat contract
that recognizes cons cells whose car and cdr correspond
to cons/p
's two arguments.
(cons-immutable/c
contract contract
)
CONTRACT
cons-immutable/c
accepts two contracts (or predicates
that are converted to flat contracts
via flat-contract
) and returns a contract that
recognizes immutable cons cells whose car and cdr
correspond to cons-immutable/c
's two arguments.
In contrast to cons/p
, cons-immutable/c
accepts arbitrary contracts, not just flat contracts.
Beware, however, that when a value is applied to this
contract, the result will not be
to the
input.eq?
(list/p
flat-contract
···)
FLAT-CONTRACT
list/p
accepts an arbitrary
number of flat contracts (or predicates that are converted to
flat contracts via flat-contract
) and returns a
flat contract that recognizes for lists whose length is the same as
the number of arguments to
list/p
and whose elements match those arguments.
(list-immutable/c
flat-contract
···)
CONTRACT
list-immutable/c
accepts an arbitrary
number of contracts (or predicates that are converted to
flat contracts via flat-contract
) and returns a
contract that recognizes for lists whose length is the same
as the number of arguments to
list-immutable/c
and whose elements match those arguments.
In contrast to list/p
, list-immutable/c
accepts arbitrary contracts, not just flat contracts.
Beware, however, that when a value is applied to this
contract, the result will not be
to the
input.eq?
(
SYNTAX
flat-rec-contract
name flat-contract ···
)
Each flat-rec-contract
form constructs a flat
recursive contract. The first argument is the name of the
contract and the following arguments are flat contract
expressions that may refer to name
.
As an example, this contract:
(flat-rec-contract sexp (cons/c sexp sexp)number?
symbol?
)
is a flat contract that checks for (a limited form of)
s-expressions. It says that an sexp
is either
two sexp
combined with
, or a number,
or a symbol.cons
(
SYNTAX
flat-murec-contract
([name flat-contract ···] ···) body ···
)
The flat-murec-contract
form is a generalization
of flat-rec-contracts
for defining several
mutually recursive flat contracts simultaneously.
Each of the names is visible in the
entire flat-murec-contract
and the result of the
final body expression is the result of the entire form.
(anaphoric-contracts
)
CONTRACT CONTRACT
(anaphoric-contracts
'equal
)
CONTRACT CONTRACT
Returns two linked anaphoric contracts. The first allows all values, and the second only allows values that the first has previously seen.
->
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 ··· (values
expr ···))
| (->* (expr ···) (expr ···))
| (->* (expr ···) any)
| (->* (expr ···) expr (expr ···))
| (->* (expr ···) expr any)
| (->c expr expr)
| (->d expr ··· expr)
| (->d* (expr ···) expr)
| (->d* (expr ···) expr expr)
| (opt-> (expr ···) (expr ···) expr)
| (opt->* (expr ···) (expr ···) any)
| (opt->* (expr ···) (expr ···) (expr ···))
where expr
is any expression.
(
SYNTAX
->
expr ···
)
(
SYNTAX
->
expr ···any
)
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. Except for the
memory performance, this is the same as using any?
in the result.
The final case of ->
expressions
treats
as a local keyword - that is, you
may not return multiple values to this position, instead if
the word values
syntactically appears in the in
the last argument to values
->
the function is treated as
a multiple value return (this is a shorthand for the two
argument variant on ->*
).
(
SYNTAX
->*
(expr ···) (expr ···)
)
(
SYNTAX
->*
(expr ···) any
)
(
SYNTAX
->*
(expr ···) expr (expr ···)
)
(
SYNTAX
->*
(expr ···) expr any
)
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. The final argument can
be any
which, like ->
means that no
contract is enforced on the result of the function and
tail-recursion is preserved.
(
SYNTAX
->d
expr ···
)
(
SYNTAX
->d*
(expr ···) expr)
)
(
SYNTAX
->d*
(expr ···) expr expr
)
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
.
(
CONTRACT-CASE->
case->
arrow-contract-expr ···
)
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*
.
(
SYNTAX
opt->
(req-contracts ···) (opt-contracts ···) res-contract)
)
(
SYNTAX
opt->*
(req-contracts ···) (opt-contracts ···) (res-contracts ···)
)
(
SYNTAX
opt->*
(req-contracts ···) (opt-contracts ···) any
)
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.
The req-contracts
expressions,
the opt-contracts
expressions, and
the res-contract
expressions can be any expression
that evaluates to a contract value.
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. A result
of any
means any value or any number of values may
be returned, and the contract does not inhibit
tail-recursion.
This section describes contracts on classes and objects. Here is the basic shape of an object contract:
contract-expr ::== ···
| (object-contract meth/field-spec ···)
meth/field-spec ::==
(meth-name meth-contract)
| (field field-name contract-expr)
meth-contract ::==
(opt-> (required-contract-expr ···)
(optional-contract-expr ···)
any)
(opt-> (required-contract-expr ···)
(optional-contract-expr ···)
result-contract-expr)
| (opt->* (required-contract-expr ···)
(optional-contract-expr ···)
(result-contract-expr ···))
| (case-> meth-arrow-contract ···)
| meth-arrow-contract
meth-arrow-contract ::==
(-> dom-contract-expr ··· rng-contract-expr)
| (-> dom-contract-expr ··· (values
rng-contract-expr ···))
| (->* (dom-contract-expr ···) (rng-contract-expr ···))
| (->* (dom-contract-expr ···) rest-arg-contract-expr (rng-contract-expr ···))
| (->d dom-contract-expr ··· rng-contract-proc-expr)
| (->d* (dom-contract-expr ···) rng-contract-proc-expr)
| (->d* (dom-contract-expr ···) rest-contract-expr rng-contract-proc-expr)
Each of the contracts for methods has the same semantics as the corresponding function contract (discussed above), but the syntax of the method contract must be written directly in the body of the object-contract (much like the way that methods in class definitions use the same syntax as regular function definitions, but cannot be arbitrary procedures).
mixin-contract
is a
contract that recognizes 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
···)
CONTRACT
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.
There are three special forms that attach contract
specification to values: provide/contract
,
define/contract
, and contract
.
(
SYNTAX
provide/contract
p/c-item ···
)
p/c-item is one of (struct identifier ((identifier contract-expr) ···)) (rename id id contract-expr) (id contract-expr)
A provide/contract
form 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
.
The provide/contract
form treats modules as units
of blame. The module that defines the provided variable is
expected to meet the (co-variant) positions of the
contract. Each module that imports the provided variable
must obey the negative (contra-variant) positions of the
contract.
Only uses of the contracted variable outside the module are checked.
The rename
form of a provide/contract
exports the first variable (the internal name) with the name
specified by the second variable (the external name).
The struct
form of a provide/contract
clause provides a structure definition. Each field has a
contract that dictates the contents of the fields.
(
SYNTAX
define/contract
id contract-expr init-value-expr
)
The define/contract
form attaches the contract
contract-expr
to init-value-expr
and binds
that to id
.
The define/contract
form treats individual
definitions as units of blame. The definition itself is
responsible for positive (co-variant) positions of the
contract and each reference to id
(including those
in the initial value expression) must meet the negative
positions of the contract.
Error messages with define/contract
are not as
clear as those provided by provide/contract
because
define/contract
cannot detect the name of the
definition where the reference to the defined variable
occurs. Instead, it uses the source location of the
reference to the variable as the name of that definition.
(
SYNTAX
contract
contract-expr to-protect-expr positive-blame negative-blame
)
(
SYNTAX
contract
contract-expr to-protect-expr positive-blame negative-blame contract-source
)
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 is a contract (ie, constructed with one of the
combinators described in this section).
This predicate returns true when its argument is a contract
that has been constructed with flat-contract
(and
thus is essentially just a predicate).
(flat-contract-predicate
value
)
SELECTOR
This function extracts the predicate from a flat contract.