some edits to the contract guide
svn: r8245
This commit is contained in:
parent
a4cd1cdbae
commit
6f2791a503
|
@ -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)
|
||||
|
|
|
@ -133,6 +133,11 @@
|
|||
margin-right: 0em;
|
||||
}
|
||||
|
||||
.insetpara {
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.toclink {
|
||||
text-decoration: none;
|
||||
color: blue;
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user