Improve Guide chapter 7

* Typos/grammar
 * Fix breakdown of contract error message
 * Show `struct/dc` instead of deprecated lazy contracts
This commit is contained in:
Asumu Takikawa 2013-03-01 05:15:04 -05:00
parent 14c77c39d2
commit ef4b3feb8d
3 changed files with 40 additions and 40 deletions

View File

@ -62,7 +62,7 @@ arguments: @racket[char?]. }
@item{The last one is a single contract: the result of the function.}
]
Note if a default value does not satisfy a contract, you won't get a
Note that if a default value does not satisfy a contract, you won't get a
contract error for this interface. If you can't trust yourself to get
the initial value right, you need to communicate the initial value
across a boundary.
@ -71,7 +71,7 @@ arguments: @racket[char?]. }
The @racket[max] operator consumes at least one real number, but it
accepts any number of additional arguments. You can write other such
functions using a ``rest'' argument, such as in @racket[max-abs]:
functions using a @tech{rest argument}, such as in @racket[max-abs]:
@margin-note{See @secref["rest-args"] for an introduction to rest
arguments.}
@ -424,7 +424,7 @@ racket
The @racket[->i] contract combinator can also ensure that a
function only modifies state according to certain
constraints. For example, consider this contract
(it is a slightly simplified from the function
(it is a slightly simplified version from the function
@racket[preferences:add-panel] in the framework):
@racketblock[
(->i ([parent (is-a?/c area-container-window<%>)])
@ -614,7 +614,7 @@ because the given function accepts only one argument.
The correct contract uses the @racket[unconstrained-domain->]
combinator, which specifies only the range of a function, not its
domain. It is then possible to combine this contract with an arity test to
specify the correct @racket[n-step]'s contract:
specify the correct contract for @racket[n-step]:
@racketblock[
(provide
(contract-out

View File

@ -10,7 +10,7 @@
A mathematical function has a @deftech{domain} and a
@deftech{range}. The domain indicates the kind of values that the
function can accept as arguments, and the range indicates the kind of
values that it produces. The conventional notation for a describing a
values that it produces. The conventional notation for describing a
function with its domain and range is
@racketblock[
@ -63,7 +63,7 @@ parties is to blame.
If a client module were to apply @racket[deposit] to @racket['millions],
it would violate the contract. The contract-monitoring system would
catch this violation and blame client for breaking the contract with
catch this violation and blame the client for breaking the contract with
the above module. In contrast, if the @racket[balance] function were
to return @racket['broke], the contract-monitoring system
would blame the server module.
@ -75,7 +75,7 @@ combinator}, which combines other contracts to form a contract.
@section{Styles of @racket[->]}
If you are used to mathematical function, you may prefer a contract
If you are used to mathematical functions, you may prefer a contract
arrow to appear between the domain and the range of a function, not
at the beginning. If you have read @|HtDP|, you have seen this many
times. Indeed, you may have seen contracts such as these in other
@ -410,11 +410,11 @@ With this little change, the error message becomes quite readable:
In general, each contract error message consists of six sections:
@itemize[@item{a name for the function or method associated with the contract
and either the phrase ``contract violation'' or ``violated it's contract''
depending on whether the contract was violated by the server or the
client; e.g. in the previous example: @lines[0 1]}
@item{a description of the precise aspect of the contract that was violated, @lines[1 1]}
@item{the complete contract plus a path into it showing which aspect was violated, @lines[2 2]}
@item{the module where the contract was put (or, more generally, the boundary that the contract mediates), @lines[4 1]}
@item{who was blamed, @lines[5 1]}
@item{and the source location where the contract appears. @lines[6 1]}]
and either the phrase ``contract violation'' or ``broke its contract''
depending on whether the contract was violated by the client or the
server; e.g. in the previous example: @lines[0 1]}
@item{a description of the precise aspect of the contract that was violated, @lines[1 2]}
@item{the complete contract plus a path into it showing which aspect was violated, @lines[3 2]}
@item{the module where the contract was put (or, more generally, the boundary that the contract mediates), @lines[5 1]}
@item{who was blamed, @lines[6 1]}
@item{and the source location where the contract appears. @lines[7 1]}]

View File

@ -166,7 +166,7 @@ racket
(define (bst? b) (bst-between? b -inf.0 +inf.0))
(provide (struct node (val left right)))
(provide (struct-out node))
(provide (contract-out
[bst? (any/c . -> . boolean?)]
[in? (number? bst? . -> . boolean?)]))
@ -195,19 +195,16 @@ that @racket[in?] looks at, we can still guarantee that
the tree is at least partially well-formed, but without
changing the complexity.
To do that, we need to use @racket[define-contract-struct] in place of
@racket[struct]. Like @racket[struct] (and more like
@racket[define-struct]), @racket[define-contract-struct] defines a
maker, predicate, and selectors for a new structure. Unlike
@racket[define-struct], it also defines contract combinators, in this
case @racket[node/c] and @racket[node/dc]. Also unlike
@racket[define-struct], it does not allow mutators, making its structs
always immutable.
To do that, we need to use @racket[struct/dc] to define
@racket[bst-between?]. Like @racket[struct/c], @racket[struct/dc] defines a
contract for a structure. Unlike
@racket[struct/c], it allows fields to be marked as lazy, so that
the contracts are only checked when the matching selector is called.
Also, it does not allow mutable fields to be marked as lazy.
The @racket[node/c] function accepts a contract for each
The @racket[struct/dc] form accepts a contract for each
field of the struct and returns a contract on the
struct. More interestingly, the syntactic
form @racket[node/dc] allows us to write dependent
struct. More interestingly, @racket[struct/dc] allows us to write dependent
contracts, i.e., contracts where some of the contracts on
the fields depend on the values of other fields. We can use
this to define the binary search tree contract:
@ -215,7 +212,7 @@ this to define the binary search tree contract:
@racketmod[
racket
(define-contract-struct node (val left right))
(struct node (val left right))
(code:comment "determines if `n' is in the binary search tree `b'")
(define (in? n b) ... as before ...)
@ -225,25 +222,28 @@ racket
(code:comment "whose values are between low and high")
(define (bst-between/c low high)
(or/c null?
(node/dc [val (between/c low high)]
[left (val) (bst-between/c low val)]
[right (val) (bst-between/c val high)])))
(struct/dc node [val (between/c low high)]
[left (val) #:lazy (bst-between/c low val)]
[right (val) #:lazy (bst-between/c val high)])))
(define bst/c (bst-between/c -inf.0 +inf.0))
(provide make-node node-left node-right node-val node?)
(provide (struct-out node))
(provide (contract-out
[bst/c contract?]
[in? (number? bst/c . -> . boolean?)]))
]
In general, each use of @racket[node/dc] must name the
In general, each use of @racket[struct/dc] must name the
fields and then specify contracts for each field. In the
above, the @racket[val] field is a contract that accepts
values between @racket[low] and @racket[high].
The @racket[left] and @racket[right] fields are
dependent on the value of the @racket[val] field,
indicated by their second sub-expressions. Their contracts
indicated by their second sub-expressions. They are
also marked with the @racket[#:lazy] keyword to indicate
that they should be checked only when the appropriate
accessor is called on the struct instance. Their contracts
are built by recursive calls to
the @racket[bst-between/c] function. Taken together,
this contract ensures the same thing that
@ -263,8 +263,8 @@ body to be a contract and then optimizes that contract.
@racketblock[
(define-opt/c (bst-between/c low high)
(or/c null?
(node/dc [val (between/c low high)]
[left (val) (bst-between/c low val)]
[right (val) (bst-between/c val high)])))
(struct/dc node [val (between/c low high)]
[left (val) #:lazy (bst-between/c low val)]
[right (val) #:lazy (bst-between/c val high)])))
]