bare bones documentation of the contract library's struct properties

svn: r16585
This commit is contained in:
Robby Findler 2009-11-06 22:31:46 +00:00
parent d2f16e3828
commit bf911e8c7a

View File

@ -941,8 +941,10 @@ Compare that to the projection for our function contract:
@schemeblock[
(define (int->int-proj pos neg src-info name positive-position?)
(let ([dom (int-proj neg pos src-info name (not positive-position?))]
[rng (int-proj pos neg src-info name positive-position?)])
(let ([dom (int-proj neg pos src-info
name (not positive-position?))]
[rng (int-proj pos neg src-info
name positive-position?)])
(lambda (f)
(if (and (procedure? f)
(procedure-arity-includes? f 1))
@ -998,8 +1000,10 @@ returns a contract for functions between them.
@schemeblock[
(define (make-simple-function-contract dom-proj range-proj)
(lambda (pos neg src-info name positive-position?)
(let ([dom (dom-proj neg pos src-info name (not positive-position?))]
[rng (range-proj pos neg src-info name positive-position?)])
(let ([dom (dom-proj neg pos src-info
name (not positive-position?))]
[rng (range-proj pos neg src-info
name positive-position?)])
(lambda (f)
(if (and (procedure? f)
(procedure-arity-includes? f 1))
@ -1021,7 +1025,7 @@ the contract library primitives below.
@defproc[(make-proj-contract [name any/c]
[proj (or/c (-> symbol? symbol? any/c any/c any/c)
(-> symbol? symbol? any/c any/c boolean? any/c))]
[first-order-test (any/c . -> . any/c)])
[first-order-test (-> any/c any/c)])
contract?]{
Builds a new contract.
@ -1043,8 +1047,13 @@ when the projection is invoked. If it returns true,
the value may or may not violate the contract, but any
violations must not be signaled immediately.
From the example above, the predicate should accept unary
functions, but reject all other values.}
This function is a convenience function, implemented
using @scheme[proj-prop], @scheme[name-prop],
@scheme[first-order-prop], and @scheme[stronger-prop].
Consider using those directly (as well as @scheme[flat-prop] as necessary),
as they allow more flexibility
and generally produce more efficient contracts.
}
@defproc[(build-compound-type-name [c/s any/c] ...) any]{
@ -1112,6 +1121,91 @@ to build an actual error message.}
% contract-stronger?
}
@subsection{Contracts as structs}
A contract is an arbitrary struct that has all of the
struct properties
(see @secref["structprops"] in the reference manual)
in this section
(except that @scheme[flat-prop] is optional).
Generally speaking, the contract should be a struct with
fields that specialize the contract in some way and then
properties that implement all of the details of checking
the contract and reporting errors, etc.
For example, an @scheme[between/c] contract is a struct that
holds the bounds on the number and then has the properties below
that inspect the bounds and take the corresponding action
(the @scheme[proj-prop] checks the numbers, the @scheme[name-prop]
constructs a name to print out for the contract, etc.).
@deftogether[(@defthing[proj-prop struct-type-property?]
@defproc[(proj-pred? [v any/c]) boolean?]{}
@defproc[(proj-get [v proj-pred?])
(-> proj-prop?
(-> symbol? symbol? (or/c #f syntax?) string? boolean?
(-> any/c any/c)))]{})]{
This is the workhorse property that implements the contract.
The property should be bound to a function that accepts
the struct and then returns a projection, as described
in the docs for @scheme[make-proj-contract] above.
}
@deftogether[(@defthing[name-prop struct-type-property?]{}
@defproc[(name-pred? [v any/c]) boolean?]{}
@defproc[(name-get [v name-pred?]) (-> name-pred? printable/c)]{})]{
This property should be a function that accepts the struct and returns
an s-expression representing the name of the property.
@mz-examples[#:eval (contract-eval)
(write (between/c 1 10))
(let ([c (between/c 1 10)])
((name-get c) c))]
}
@deftogether[(@defthing[stronger-prop struct-type-property?]{}
@defproc[(stronger-pred? [v any/c]) boolean?]{}
@defproc[(stronger-get [v stronger-pred?]) (-> stronger-pred? stronger-pred? boolean?)]{})]{
This property is used when optimizing contracts, in order to tell if some contract is stronger than another one.
In some situations, if a contract that is already in place is stronger than one about to be put in place,
then the new one is ignored.
}
@deftogether[(@defthing[flat-prop struct-type-property?]{}
@defproc[(flat-pred? [v any/c]) boolean?]{}
@defproc[(flat-get [v flat-pred?]) (-> flat-pred? (-> any/c boolean?))]{})]{
This property should only be present if the contract is a flat contract. In the case that it is
a flat contract, the value of the property should be a predicate that determines if the
contract holds.
@mz-examples[#:eval (contract-eval)
(flat-pred? (-> integer? integer?))
(let ([c (between/c 1 10)]
[pred ((flat-get c) c)])
(list (pred 9)
(pred 11)))]
}
@deftogether[(@defthing[first-order-prop struct-type-property?]{}
@defproc[(first-order-pred? [v any/c]) boolean?]{}
@defproc[(first-order-get [v proj-pred?]) (-> first-order-pred? (-> any/c boolean?))]{})]{
This property is used with @scheme[or/c] to determine which branch of the
@scheme[or/c] applies. These don't have to be precise (i.e., returning @scheme[#f] is always safe),
but the more often a contract can honestly return @scheme[#t], the more often
it will work with @scheme[or/c].
For example, function contracts typically check arity in their @scheme[first-order-prop]s.
}
@; ------------------------------------------------------------------------
@section{Contract Utilities}