some edits to the contract guide

svn: r8245
This commit is contained in:
Matthew Flatt 2008-01-07 12:48:38 +00:00
parent a4cd1cdbae
commit 6f2791a503
6 changed files with 63 additions and 47 deletions

View File

@ -235,13 +235,14 @@
litchar
verbatim)
(provide image onscreen menuitem defterm
(provide image onscreen menuitem defterm emph
schemefont schemevalfont schemeresultfont schemeidfont schemevarfont
schemeparenfont schemekeywordfont schememetafont schememodfont
filepath exec envvar Flag DFlag PFlag DPFlag
indexed-file indexed-envvar
link procedure
idefterm)
idefterm
inset-flow)
;; String String *-> Element
;; an in-lined image, relative to the current directory
@ -255,6 +256,8 @@
(make-element 'sf (decode-content str)))
(define (menuitem menu item)
(make-element 'sf (list menu "|" item)))
(define (emph . str)
(make-element 'italic (decode-content str)))
(define (defterm . str)
(make-element 'italic (decode-content str)))
(define (idefterm . str)
@ -313,6 +316,11 @@
(define (t . str)
(decode-paragraph str))
(define (inset-flow . c)
(make-blockquote
"insetpara"
(flow-paragraphs (decode-flow c))))
;; ----------------------------------------
(define (gen-absolute-tag)

View File

@ -133,6 +133,11 @@
margin-right: 0em;
}
.insetpara {
margin-left: 1em;
margin-right: 1em;
}
.toclink {
text-decoration: none;
color: blue;

View File

@ -30,21 +30,21 @@ Several clients used your module. Others used their
modules. And all of a sudden one of them sees this error
message:
@schemeerror{bank-client broke the contract (-> ??? any)
it had with myaccount on deposit;
expected <???>, given: -10}
@inset-flow{@schemeerror{bank-client broke the contract (-> ??? any)
it had with myaccount on deposit; expected <???>, given: -10}}
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?
Clearly, @scheme[bank-client] is a module that uses @scheme[myaccount]
but what are the @schemeerror{?}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?
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:
For this situation, PLT Scheme provides @deftech{flat named
contracts}. The use of ``contract'' in this term 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, which is to name
the contract so that error messages become intelligible:
@schememod[
scheme
@ -59,23 +59,23 @@ scheme
(define (deposit a) ...)
]
With this little change, the error message becomes all of
With this little change, the error message becomes all of the
sudden quite readable:
@schemeerror{bank-client broke the contract (-> amount any)
it had with myaccount on deposit;
expected <amount>, given: -10"}
@inset-flow{@schemeerror{bank-client broke the contract (-> amount
any) it had with myaccount on deposit; expected <amount>, given: -10"}}
@question[#:tag "optional"]{What about optional arguments?}
Take a look at this excerpt from a string-processing module, inspired by the
Scheme cookbook:
@link["http://schemecookbook.org"]{Scheme cookbook}:
@schememod[
scheme
(provide/contract
;; pad the given str left and right with
;; the (optional) char so that it is centered
(code:comment #, @t{pad the given str left and right with})
(code:comment #, @t{the (optional) char so that it is centered})
[string-pad-center (->* (string? natural-number/c)
(char?)
string?)])
@ -126,7 +126,7 @@ the arguments depend on each other.
To specify such contracts combine @scheme[case->] with
the other function contract combinators, like we did in
the @scheme[substring1] function above.
}
@question[#:tag "rest-args"]{What about rest arguments?}
@ -147,7 +147,7 @@ Here is the contract:
]
The @scheme[->*] contract combinator empowers you to specify
functions that consume a variable number of arguments or functions like
@scheme[plus], which consume "at least this number" of arguments but
@scheme[plus], which consume ``at least this number'' of arguments but
an arbitrary number of additional arguments.
The contracts for the required arguments are enclosed in the first
@ -606,9 +606,9 @@ glance, this appears to suggest a contract that assigns a
(listof any/c)
(or/c number? false/c))
]
This contract, however, says that the function must accept <em>any</em>
number of arguments, not a <em>specific</em> but
@italic{undetermined} number. Thus, applying @scheme[n-step] to
This contract, however, says that the function must accept @emph{any}
number of arguments, not a @emph{specific} but
@emph{undetermined} number. Thus, applying @scheme[n-step] to
@scheme[(lambda (x) x)] and @scheme[(list 1)] breaks the contract
because the given function accepts only one argument.

View File

@ -10,13 +10,11 @@
@question{What about @scheme[set!] on variables provided via @scheme[provide/contract]?}
The contract library assumes that variables exported via
@scheme[provide/contract] are not assigned to, but does not
enforce it. Accordingly, if you try to @scheme[set!] those
variables, you may find unexpected behavior. As an example,
consider this program (running in the MzScheme language of
DrScheme):
@scheme[provide/contract] are not assigned to, but does not enforce
it. Accordingly, if you try to @scheme[set!] those variables, you may
find unexpected behavior. Consider the following example:
@schemeblock[
@interaction[
(module server scheme
(define (inc-x!) (set! x (+ x 1)))
(define x 0)
@ -35,10 +33,9 @@ DrScheme):
(require 'client)
]
When it runs, both calls to @scheme[print-latest]
print @scheme[0], even though the value
of @scheme[x] has been incremented (and the change is
visible inside the module @scheme[x]).
Both calls to @scheme[print-latest] print @scheme[0], even though the
value of @scheme[x] has been incremented (and the change is visible
inside the module @scheme[x]).
To work around this, export accessor functions, rather than
exporting the function directly, like this:

View File

@ -97,10 +97,10 @@ like that."
@question[#:tag "dots"]{What are the dots in contracts about?}
If you are used to mathematics, you like the arrow in between the domain
and the range of a function, not at the beginning. If you have read "How
to Design Programs," you have seen this many times. Indeed, you may have
seen contracts such as these in other people's code:
If you are used to mathematics, you like the arrow in 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 people's code:
@schemeblock[
(provide/contract
@ -159,9 +159,9 @@ the @scheme[amount?] predicate itself, with a contract
saying that it accepts an arbitrary value and returns a
boolean.
In this case, we could also have used @scheme[natural-number/c], which is
a contract defined in "contract.ss" that is equivalent to @scheme[amount]
(modulo the name):
In this case, we could also have used @scheme[natural-number/c], which
is a contract defined in @schememodname[scheme/contract] that is
equivalent to @scheme[amount] (modulo the name):
@schememod[
scheme
@ -174,7 +174,7 @@ scheme
(define (deposit a) (set! this (+ this a)))
]
Lesson: look up the built-in contracts.
Lesson: learn about the built-in contracts in @schememodname[scheme/contract].
@question[#:tag "and-or"]{Are @scheme[and/c] and @scheme[or/c] contract combinators? What of @scheme[listof]?}
@ -237,8 +237,8 @@ the function consumes a number and produces a string.
The contract of the exported function @scheme[format-nat] is more
interesting than the one of @scheme[format-number]. It consumes only
natural numbers. Its range contract promises a string that has a dot "." in the
third position from the right.
natural numbers. Its range contract promises a string that has a
@litchar{.} in the third position from the right.
@(exercise) Strengthen the promise of the range contract for
@scheme[format-nat] so that it admits only strings with digits and a single

View File

@ -162,6 +162,9 @@ sub-form in a procedure being documented).}
@scheme[schemefont], but colored as meta-syntax, such as backquote or
unquote.}
@defproc[(schemeerror [pre-content any/c] ...) element?]{Like
@scheme[schemefont], but colored as error-message text.}
@defproc[(procedure [pre-content any/c] ...) element?]{Typesets
@tech{decode}d @scheme[pre-content] as a procedure name in a REPL
result (e.g., in typewriter font with a @litchar{#<procedure:} prefix
@ -574,6 +577,9 @@ the containing class/interface.}
@; ------------------------------------------------------------------------
@section{Various String Forms}
@defproc[(emph [pre-content any/c] ...) element?]{Typesets the
@tech{decode}d @scheme[pre-content] with emphasis (e.g., in italic).}
@defproc[(defterm [pre-content any/c] ...) element?]{Typesets the
@tech{decode}d @scheme[pre-content] as a defined term (e.g., in
italic). Consider using @scheme[deftech] instead, though, so that uses