fill in some guide sections
svn: r9871
This commit is contained in:
parent
61a80e85fb
commit
2b48cb0a4d
|
@ -356,18 +356,20 @@
|
||||||
;; Like a toplevel (eval `(begin ,@exprs)), but the language that is used may
|
;; Like a toplevel (eval `(begin ,@exprs)), but the language that is used may
|
||||||
;; not have a begin.
|
;; not have a begin.
|
||||||
(define (eval* exprs)
|
(define (eval* exprs)
|
||||||
(if (null? exprs)
|
(call-with-continuation-prompt
|
||||||
(void)
|
(lambda ()
|
||||||
(let ([deftag (default-continuation-prompt-tag)])
|
(if (null? exprs)
|
||||||
(let loop ([expr (car exprs)] [exprs (cdr exprs)])
|
(void)
|
||||||
(if (null? exprs)
|
(let ([deftag (default-continuation-prompt-tag)])
|
||||||
(eval expr)
|
(let loop ([expr (car exprs)] [exprs (cdr exprs)])
|
||||||
(begin
|
(if (null? exprs)
|
||||||
(call-with-continuation-prompt
|
(eval expr)
|
||||||
(lambda () (eval expr))
|
(begin
|
||||||
deftag
|
(call-with-continuation-prompt
|
||||||
(lambda (x) (abort-current-continuation deftag x)))
|
(lambda () (eval expr))
|
||||||
(loop (car exprs) (cdr exprs))))))))
|
deftag
|
||||||
|
(lambda (x) (abort-current-continuation deftag x)))
|
||||||
|
(loop (car exprs) (cdr exprs))))))))))
|
||||||
|
|
||||||
(define (evaluate-program program limits uncovered!)
|
(define (evaluate-program program limits uncovered!)
|
||||||
(when uncovered!
|
(when uncovered!
|
||||||
|
|
|
@ -144,10 +144,14 @@
|
||||||
(loop (extract s cdr car)
|
(loop (extract s cdr car)
|
||||||
(list (syntax->datum (datum->syntax #f (extract s cdr cdr car)))))]
|
(list (syntax->datum (datum->syntax #f (extract s cdr cdr car)))))]
|
||||||
[else
|
[else
|
||||||
(let ([r (with-handlers ([exn:fail? (lambda (e)
|
(let ([r (with-handlers ([(lambda (x)
|
||||||
(list (exn-message e)
|
(not (exn:break? x)))
|
||||||
(get-output ev)
|
(lambda (e)
|
||||||
(get-error-output ev)))])
|
(list (if (exn? e)
|
||||||
|
(exn-message e)
|
||||||
|
(format "uncaught exception: ~s" e))
|
||||||
|
(get-output ev)
|
||||||
|
(get-error-output ev)))])
|
||||||
(list (let ([v (do-plain-eval ev s #t)])
|
(list (let ([v (do-plain-eval ev s #t)])
|
||||||
(make-reader-graph (copy-value v (make-hasheq))))
|
(make-reader-graph (copy-value v (make-hasheq))))
|
||||||
(get-output ev)
|
(get-output ev)
|
||||||
|
|
|
@ -2042,6 +2042,7 @@
|
||||||
|
|
||||||
(define (bib-entry #:key key
|
(define (bib-entry #:key key
|
||||||
#:title title
|
#:title title
|
||||||
|
#:is-book? [is-book? #f]
|
||||||
#:author [author #f]
|
#:author [author #f]
|
||||||
#:location [location #f]
|
#:location [location #f]
|
||||||
#:date [date #f]
|
#:date [date #f]
|
||||||
|
@ -2055,12 +2056,19 @@
|
||||||
(append (decode-content (list author))
|
(append (decode-content (list author))
|
||||||
(list ", "))
|
(list ", "))
|
||||||
null)
|
null)
|
||||||
(list 'ldquo)
|
(if is-book?
|
||||||
(decode-content (list title))
|
null
|
||||||
|
(list 'ldquo))
|
||||||
|
(if is-book?
|
||||||
|
(list (italic title))
|
||||||
|
(decode-content (list title)))
|
||||||
(list (if location
|
(list (if location
|
||||||
","
|
","
|
||||||
".")
|
"."))
|
||||||
'rdquo)
|
|
||||||
|
(if is-book?
|
||||||
|
null
|
||||||
|
(list 'rdquo))
|
||||||
(if location
|
(if location
|
||||||
(cons " "
|
(cons " "
|
||||||
(append
|
(append
|
||||||
|
|
|
@ -6,18 +6,18 @@
|
||||||
(for-label scheme/contract)
|
(for-label scheme/contract)
|
||||||
(for-label scheme/gui))
|
(for-label scheme/gui))
|
||||||
|
|
||||||
@title{Examples}
|
@title[#:tag "contracts-examples"]{Examples}
|
||||||
|
|
||||||
This section illustrates the current state of PLT Scheme's contract
|
This section illustrates the current state of PLT Scheme's contract
|
||||||
implementation with a series of examples from Mitchell and McKim's text
|
implementation with a series of examples from @italic{Design by
|
||||||
book "Design by Contract, by Example" [Addison and Wesley, 2002].
|
Contract, by Example} @cite["Mitchell02"].
|
||||||
|
|
||||||
Mitchell and McKim's principles for design by contract DbC are derived
|
Mitchell and McKim's principles for design by contract DbC are derived
|
||||||
from the 1970s style algebraic specifications. The overall goal of DbC is
|
from the 1970s style algebraic specifications. The overall goal of DbC is
|
||||||
to specify the constructors of an algebra in terms of its
|
to specify the constructors of an algebra in terms of its
|
||||||
observers. While we reformulate Mitchell and McKim's terminology and
|
observers. While we reformulate Mitchell and McKim's terminology and
|
||||||
we use a mostly applicative, we
|
we use a mostly applicative, we
|
||||||
retain their terminology of "classes" and "objects":
|
retain their terminology of ``classes'' and ``objects'':
|
||||||
|
|
||||||
@itemize{
|
@itemize{
|
||||||
@item{@bold{Separate queries from commands.}
|
@item{@bold{Separate queries from commands.}
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
(for-label scheme/contract)
|
(for-label scheme/contract)
|
||||||
(for-label scheme/gui))
|
(for-label scheme/gui))
|
||||||
|
|
||||||
@title{Contracts on Functions in General}
|
@title[#:tag "contracts-general-functions"]{Contracts on Functions in General}
|
||||||
|
|
||||||
@ctc-section[#:tag "flat-named-contracts"]{Contract error messages that contain ``...''}
|
@ctc-section[#:tag "flat-named-contracts"]{Contract Error Messages that Contain ``???''}
|
||||||
|
|
||||||
You wrote your module. You added contracts. You put them into the interface
|
You wrote your module. You added contracts. You put them into the interface
|
||||||
so that client programmers have all the information from interfaces. It's a
|
so that client programmers have all the information from interfaces. It's a
|
||||||
|
@ -65,7 +65,7 @@ sudden quite readable:
|
||||||
@inset-flow{@schemeerror{bank-client broke the contract (-> amount
|
@inset-flow{@schemeerror{bank-client broke the contract (-> amount
|
||||||
any) it had with myaccount on deposit; expected <amount>, given: -10}}
|
any) it had with myaccount on deposit; expected <amount>, given: -10}}
|
||||||
|
|
||||||
@ctc-section[#:tag "optional"]{Optional arguments}
|
@ctc-section[#:tag "optional"]{Optional Arguments}
|
||||||
|
|
||||||
Take a look at this excerpt from a string-processing module, inspired by the
|
Take a look at this excerpt from a string-processing module, inspired by the
|
||||||
@link["http://schemecookbook.org"]{Scheme cookbook}:
|
@link["http://schemecookbook.org"]{Scheme cookbook}:
|
||||||
|
@ -121,7 +121,7 @@ arguments: @scheme[char?]. }
|
||||||
yourself, you need to communicate across boundaries for
|
yourself, you need to communicate across boundaries for
|
||||||
everything you write.
|
everything you write.
|
||||||
|
|
||||||
@ctc-section[#:tag "rest-args"]{Rest arguments}
|
@ctc-section[#:tag "rest-args"]{Rest Arguments}
|
||||||
|
|
||||||
We all know that @scheme[+] in Beginner Scheme is a function
|
We all know that @scheme[+] in Beginner Scheme is a function
|
||||||
that consumes at least two numbers but, in principle,
|
that consumes at least two numbers but, in principle,
|
||||||
|
@ -161,7 +161,7 @@ rest argument follows @scheme[#:rest]
|
||||||
contract demands a list of values; in this specific
|
contract demands a list of values; in this specific
|
||||||
examples, these values must be number.
|
examples, these values must be number.
|
||||||
|
|
||||||
@ctc-section[#:tag "keywords"]{Keyword arguments}
|
@ctc-section[#:tag "keywords"]{Keyword Arguments}
|
||||||
|
|
||||||
Sometimes, a function accepts many arguments and remembering
|
Sometimes, a function accepts many arguments and remembering
|
||||||
their order can be a nightmare. To help with such functions,
|
their order can be a nightmare. To help with such functions,
|
||||||
|
@ -222,7 +222,7 @@ five keyword arguments, one for each of the keywords
|
||||||
Also, just like in a function definition, the keywords in
|
Also, just like in a function definition, the keywords in
|
||||||
the @scheme[->] may appear in any order.
|
the @scheme[->] may appear in any order.
|
||||||
|
|
||||||
@ctc-section[#:tag "optional-keywords"]{Optional keyword arguments}
|
@ctc-section[#:tag "optional-keywords"]{Optional Keyword Arguments}
|
||||||
|
|
||||||
Of course, many of the parameters in
|
Of course, many of the parameters in
|
||||||
@scheme[ask-yes-or-no-question] (from the previous question)
|
@scheme[ask-yes-or-no-question] (from the previous question)
|
||||||
|
@ -259,7 +259,7 @@ sections. In this case, we have mandatory keywords
|
||||||
putting the mandatory keywords in the first section and the
|
putting the mandatory keywords in the first section and the
|
||||||
optional ones in the second section.
|
optional ones in the second section.
|
||||||
|
|
||||||
@ctc-section[#:tag "arrow-d"]{When a function's result depends on its arguments}
|
@ctc-section[#:tag "arrow-d"]{When a Function's Result Depends on its Arguments}
|
||||||
|
|
||||||
Here is an excerpt from an imaginary (pardon the pun) numerics module:
|
Here is an excerpt from an imaginary (pardon the pun) numerics module:
|
||||||
|
|
||||||
|
@ -291,7 +291,7 @@ and @scheme[>=/c], and it pays off to look them up in the contract
|
||||||
section of the reference manual. They simplify contracts tremendously
|
section of the reference manual. They simplify contracts tremendously
|
||||||
and make them more accessible to potential clients.
|
and make them more accessible to potential clients.
|
||||||
|
|
||||||
@ctc-section[#:tag "arrow-d-args"]{When contract arguments depend on each other}
|
@ctc-section[#:tag "arrow-d-args"]{When Contract Arguments Depend on Each Other}
|
||||||
|
|
||||||
Eventually bank customers want their money back. Hence, a module that
|
Eventually bank customers want their money back. Hence, a module that
|
||||||
implements a bank account must include a method for withdrawing money. Of
|
implements a bank account must include a method for withdrawing money. Of
|
||||||
|
@ -396,7 +396,7 @@ balance. The resulting contract checks whether an account
|
||||||
has a balance that is larger or smaller, depending on the
|
has a balance that is larger or smaller, depending on the
|
||||||
given comparison operator, than the original balance.
|
given comparison operator, than the original balance.
|
||||||
|
|
||||||
@ctc-section[#:tag "arrow-d-eval-order"]{Ensuring that a function properly modifies state}
|
@ctc-section[#:tag "arrow-d-eval-order"]{Ensuring that a Function Properly Modifies State}
|
||||||
|
|
||||||
The @scheme[->d] contract combinator can also ensure that a
|
The @scheme[->d] contract combinator can also ensure that a
|
||||||
function only modifies state according to certain
|
function only modifies state according to certain
|
||||||
|
@ -515,7 +515,7 @@ In the case of @scheme[substring1], we also know that the indices
|
||||||
numeric constraints on them.
|
numeric constraints on them.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ctc-section[#:tag "multiple"]{Multiple result values}
|
@ctc-section[#:tag "multiple"]{Multiple Result Values}
|
||||||
|
|
||||||
The function @scheme[split] consumes a list of @scheme[char]s
|
The function @scheme[split] consumes a list of @scheme[char]s
|
||||||
and delivers the string that occurs before the first occurrence of
|
and delivers the string that occurs before the first occurrence of
|
||||||
|
@ -595,7 +595,7 @@ This contract is expensive to check of course. Here is a slightly
|
||||||
]
|
]
|
||||||
Click on @scheme[string-len/c] to see what it does.
|
Click on @scheme[string-len/c] to see what it does.
|
||||||
|
|
||||||
@ctc-section[#:tag "no-domain"]{Procedures of some fixed, but statically unknown arity}
|
@ctc-section[#:tag "no-domain"]{Procedures of Some Fixed, but Statically Unknown Arity}
|
||||||
|
|
||||||
Imagine yourself writing a contract for a function that accepts some other
|
Imagine yourself writing a contract for a function that accepts some other
|
||||||
function and a list of numbers that eventually applies the former to the
|
function and a list of numbers that eventually applies the former to the
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
"contracts-utils.ss"
|
"contracts-utils.ss"
|
||||||
(for-label scheme/contract))
|
(for-label scheme/contract))
|
||||||
|
|
||||||
@title{Gotchas}
|
@title[#:tag "contracts-gotchas"]{Gotchas}
|
||||||
|
|
||||||
@ctc-section{Using @scheme[set!] to assign to variables provided via @scheme[provide/contract]}
|
@ctc-section{Using @scheme[set!] to Assign to Variables Provided via @scheme[provide/contract]}
|
||||||
|
|
||||||
The contract library assumes that variables exported via
|
The contract library assumes that variables exported via
|
||||||
@scheme[provide/contract] are not assigned to, but does not enforce
|
@scheme[provide/contract] are not assigned to, but does not enforce
|
||||||
|
|
|
@ -47,7 +47,7 @@ scheme/base
|
||||||
(define amount ...)
|
(define amount ...)
|
||||||
]
|
]
|
||||||
|
|
||||||
@ctc-section[#:tag "amount0"]{A first contract violation}
|
@ctc-section[#:tag "amount0"]{A First Contract Violation}
|
||||||
|
|
||||||
Suppose the creator of @scheme[a] had written
|
Suppose the creator of @scheme[a] had written
|
||||||
@schememod[
|
@schememod[
|
||||||
|
@ -62,7 +62,7 @@ When module @scheme[a] is required, the monitoring
|
||||||
system signals a violation of the contract and
|
system signals a violation of the contract and
|
||||||
blame @scheme[a] for breaking its promises.
|
blame @scheme[a] for breaking its promises.
|
||||||
|
|
||||||
@ctc-section[#:tag "qamount"]{A subtle contract violation}
|
@ctc-section[#:tag "qamount"]{A Subtle Contract Violation}
|
||||||
|
|
||||||
Suppose the creator of @scheme[a] had written
|
Suppose the creator of @scheme[a] had written
|
||||||
@schememod[
|
@schememod[
|
||||||
|
@ -184,7 +184,7 @@ the module boundary for a second time.
|
||||||
</question>
|
</question>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ctc-section[#:tag "obligations"]{Imposing obligations on a module's clients}
|
@ctc-section[#:tag "obligations"]{Imposing Obligations on a Module's Clients}
|
||||||
|
|
||||||
On occasion, a module may want to enter a contract with
|
On occasion, a module may want to enter a contract with
|
||||||
another module only if the other module abides by certain
|
another module only if the other module abides by certain
|
||||||
|
|
|
@ -18,7 +18,7 @@ value back to the ``client'' module.
|
||||||
It is important to keep this picture in mind when you read the explanations
|
It is important to keep this picture in mind when you read the explanations
|
||||||
of the various ways of imposing contracts on functions.
|
of the various ways of imposing contracts on functions.
|
||||||
|
|
||||||
@ctc-section[#:tag "argcontract"]{Restricting the arguments of a function}
|
@ctc-section[#:tag "argcontract"]{Restricting the Arguments of a Function}
|
||||||
|
|
||||||
Functions usually don't work on all possible Scheme values but only on a
|
Functions usually don't work on all possible Scheme values but only on a
|
||||||
select subset such as numbers, booleans, etc. Here is a module that may
|
select subset such as numbers, booleans, etc. Here is a module that may
|
||||||
|
@ -96,7 +96,7 @@ combinator}. Its purpose is to combine other contracts into a contract
|
||||||
that says "this is a function @italic{and} its arguments and its result are
|
that says "this is a function @italic{and} its arguments and its result are
|
||||||
like that."
|
like that."
|
||||||
|
|
||||||
@ctc-section[#:tag "dots"]{Infix contract notation}
|
@ctc-section[#:tag "dots"]{Infix Contract Notation}
|
||||||
|
|
||||||
If you are used to mathematics, you like the arrow in between the
|
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
|
domain and the range of a function, not at the beginning. If you
|
||||||
|
@ -120,7 +120,7 @@ is really just a short-hand for
|
||||||
Of course, placing the arrow to the left of the range follows not only
|
Of course, placing the arrow to the left of the range follows not only
|
||||||
mathematical tradition but also that of typed functional languages.
|
mathematical tradition but also that of typed functional languages.
|
||||||
|
|
||||||
@ctc-section[#:tag "own"]{Rolling your own contracts for function arguments}
|
@ctc-section[#:tag "own"]{Rolling Your Own Contracts for Function Arguments}
|
||||||
|
|
||||||
The @scheme[deposit] function adds the given number to the value of
|
The @scheme[deposit] function adds the given number to the value of
|
||||||
@scheme[amount]. While the function's contract prevents clients from
|
@scheme[amount]. While the function's contract prevents clients from
|
||||||
|
@ -177,7 +177,7 @@ scheme
|
||||||
|
|
||||||
Lesson: learn about the built-in contracts in @schememodname[scheme/contract].
|
Lesson: learn about the built-in contracts in @schememodname[scheme/contract].
|
||||||
|
|
||||||
@ctc-section[#:tag "and-or"]{The @scheme[and/c], @scheme[or/c], and @scheme[listof] contract combinators}
|
@ctc-section[#:tag "and-or"]{The @scheme[and/c], @scheme[or/c], and @scheme[listof] Contract Combinators}
|
||||||
|
|
||||||
Both @scheme[and/c] and @scheme[or/c] ombine contracts and
|
Both @scheme[and/c] and @scheme[or/c] ombine contracts and
|
||||||
they do what you expect them to do.
|
they do what you expect them to do.
|
||||||
|
@ -209,7 +209,7 @@ value satisfies @scheme[number?] and @scheme[integer?] and
|
||||||
Oh, we almost forgot. What do you think @scheme[(listof char?)]
|
Oh, we almost forgot. What do you think @scheme[(listof char?)]
|
||||||
means? Hint: it is a contract!
|
means? Hint: it is a contract!
|
||||||
|
|
||||||
@ctc-section[#:tag "range"]{Restricting the range of a function}
|
@ctc-section[#:tag "range"]{Restricting the Range of a Function}
|
||||||
|
|
||||||
Consider a utility module for creating strings from banking records:
|
Consider a utility module for creating strings from banking records:
|
||||||
|
|
||||||
|
@ -280,7 +280,7 @@ scheme
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ctc-section{The difference between @scheme[any] and @scheme[any/c]}
|
@ctc-section{The Difference Between @scheme[any] and @scheme[any/c]}
|
||||||
|
|
||||||
The contract @scheme[any/c] accepts any value, and
|
The contract @scheme[any/c] accepts any value, and
|
||||||
@scheme[any] is a keyword that can appear in the range of
|
@scheme[any] is a keyword that can appear in the range of
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
"contracts-utils.ss"
|
"contracts-utils.ss"
|
||||||
(for-label scheme/contract))
|
(for-label scheme/contract))
|
||||||
|
|
||||||
@title{Contracts on Structures}
|
@title[#:tag "contracts-struct"]{Contracts on Structures}
|
||||||
|
|
||||||
Modules deal with structures in two ways. First they export
|
Modules deal with structures in two ways. First they export
|
||||||
@scheme[struct] definitions, i.e., the ability to create
|
@scheme[struct] definitions, i.e., the ability to create
|
||||||
|
@ -17,7 +17,7 @@ its fields contain values of a certain kind. This section
|
||||||
explains how to protect structs with contracts for both
|
explains how to protect structs with contracts for both
|
||||||
uses.
|
uses.
|
||||||
|
|
||||||
@ctc-section[#:tag "single-struct"]{Promising something about a specific struct}
|
@ctc-section[#:tag "single-struct"]{Promising Something About a Specific Structure}
|
||||||
|
|
||||||
Yes. If your module defines a variable to be a structure, then on export you
|
Yes. If your module defines a variable to be a structure, then on export you
|
||||||
can specify the structures shape:
|
can specify the structures shape:
|
||||||
|
@ -35,12 +35,12 @@ In this example, the module imports a library for representing positions, which
|
||||||
exports a @scheme[posn] structure. One of the @scheme[posn]s it creates
|
exports a @scheme[posn] structure. One of the @scheme[posn]s it creates
|
||||||
and exports stands for the origin, i.e., @tt{(0,0)}, of the grid.
|
and exports stands for the origin, i.e., @tt{(0,0)}, of the grid.
|
||||||
|
|
||||||
@ctc-section[#:tag "single-vector"]{Promising something about a specific vector}
|
@ctc-section[#:tag "single-vector"]{Promising Something About a Specific Vector}
|
||||||
|
|
||||||
Yes, again. See the help desk for information on @scheme[vector/c] and
|
Yes, again. See the help desk for information on @scheme[vector/c] and
|
||||||
similar contract combinators for (flat) compound data.
|
similar contract combinators for (flat) compound data.
|
||||||
|
|
||||||
@ctc-section[#:tag "define-struct"]{Ensuring that all structs are well-formed}
|
@ctc-section[#:tag "define-struct"]{Ensuring that All Structs are Well-Formed}
|
||||||
|
|
||||||
The book @link["http://www.htdp.org/"]{@italic{How to Design
|
The book @link["http://www.htdp.org/"]{@italic{How to Design
|
||||||
Programs}} teaches that @scheme[posn]s should contain only
|
Programs}} teaches that @scheme[posn]s should contain only
|
||||||
|
@ -128,7 +128,7 @@ A single change suffices:
|
||||||
Instead of exporting @scheme[p-sick] as a plain @scheme[posn?], we use a
|
Instead of exporting @scheme[p-sick] as a plain @scheme[posn?], we use a
|
||||||
@scheme[struct/c] contract to enforce constraints on its components.
|
@scheme[struct/c] contract to enforce constraints on its components.
|
||||||
|
|
||||||
@ctc-section[#:tag "lazy-contracts"]{Checking properties of data structures}
|
@ctc-section[#:tag "lazy-contracts"]{Checking Properties of Data Structures}
|
||||||
|
|
||||||
Contracts written using @scheme[struct/c] immediately
|
Contracts written using @scheme[struct/c] immediately
|
||||||
check the fields of the data structure, but sometimes this
|
check the fields of the data structure, but sometimes this
|
||||||
|
|
266
collects/scribblings/guide/control.scrbl
Normal file
266
collects/scribblings/guide/control.scrbl
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require scribble/manual
|
||||||
|
scribble/eval
|
||||||
|
"guide-utils.ss")
|
||||||
|
|
||||||
|
@(define cc-eval (make-base-eval))
|
||||||
|
|
||||||
|
@title[#:tag "control" #:style 'toc]{Exceptions and Control}
|
||||||
|
|
||||||
|
Scheme provides an especially rich set of control operations---not
|
||||||
|
only operations for raising and catching exceptions, but also
|
||||||
|
operations for grabbing and restoring portions of a computation.
|
||||||
|
|
||||||
|
@local-table-of-contents[]
|
||||||
|
|
||||||
|
@; ----------------------------------------
|
||||||
|
|
||||||
|
@section[#:tag "exns"]{Exceptions}
|
||||||
|
|
||||||
|
Whenever a run-time error occurs, an @deftech{exception} is
|
||||||
|
raised. Unless the exception is caught, then it is handled by printing
|
||||||
|
a message associated with the exception, and then escaping from the
|
||||||
|
computation.
|
||||||
|
|
||||||
|
@interaction[
|
||||||
|
(/ 1 0)
|
||||||
|
(car 17)
|
||||||
|
]
|
||||||
|
|
||||||
|
To catch an exception, use the @scheme[with-handlers] form:
|
||||||
|
|
||||||
|
@specform[
|
||||||
|
(with-handlers ([predicate-expr handler-expr] ...)
|
||||||
|
body ...+)
|
||||||
|
]{}
|
||||||
|
|
||||||
|
Each @scheme[_predicate-expr] in a handler determines a kind of
|
||||||
|
exception that is caught by the @scheme[with-handlers] form, and the
|
||||||
|
value representing the exception is passed to the handler procedure
|
||||||
|
produced by @scheme[_handler-expr]. The result of the
|
||||||
|
@scheme[_handler-expr] is the result of the @scheme[with-handlers]
|
||||||
|
expression.
|
||||||
|
|
||||||
|
For example, a divide-by-zero error raises an instance of the
|
||||||
|
@scheme[exn:fail:contract:divide-by-zero] structure type:
|
||||||
|
|
||||||
|
@interaction[
|
||||||
|
(with-handlers ([exn:fail:contract:divide-by-zero?
|
||||||
|
(lambda (exn) +inf.0)])
|
||||||
|
(/ 1 0))
|
||||||
|
(with-handlers ([exn:fail:contract:divide-by-zero?
|
||||||
|
(lambda (exn) +inf.0)])
|
||||||
|
(car 17))
|
||||||
|
]
|
||||||
|
|
||||||
|
The @scheme[error] function is one way to raise your own exception. It
|
||||||
|
packages an error message and other information into an
|
||||||
|
@scheme[exn:fail] structure:
|
||||||
|
|
||||||
|
@interaction[
|
||||||
|
(error "crash!")
|
||||||
|
(with-handlers ([exn:fail? (lambda (exn) 'air-bag)])
|
||||||
|
(error "crash!"))
|
||||||
|
]
|
||||||
|
|
||||||
|
The @scheme[exn:fail:contract:divide-by-zero] and @scheme[exn:fail]
|
||||||
|
structure types are sub-types of the @scheme[exn] structure
|
||||||
|
type. Exceptions raised by core forms and functions always raise an
|
||||||
|
instance of @scheme[exn] or one of its sub-types, but an exception
|
||||||
|
does not have to be represented by a structure. The @scheme[raise]
|
||||||
|
function lets you raise any value as an exception:
|
||||||
|
|
||||||
|
@interaction[
|
||||||
|
(raise 2)
|
||||||
|
(with-handlers ([(lambda (v) (equal? v 2)) (lambda (v) 'two)])
|
||||||
|
(raise 2))
|
||||||
|
(with-handlers ([(lambda (v) (equal? v 2)) (lambda (v) 'two)])
|
||||||
|
(/ 1 0))
|
||||||
|
]
|
||||||
|
|
||||||
|
Multiple @scheme[_predicate-expr]s in a @scheme[with-handlers] form
|
||||||
|
let you handle different kinds of exceptions in different ways. The
|
||||||
|
predicates are tried in order, and if none of them match, then the
|
||||||
|
exception is propagated to enclosing contexts.
|
||||||
|
|
||||||
|
@interaction[
|
||||||
|
(define (always-fail n)
|
||||||
|
(with-handlers ([even? (lambda (v) 'even)]
|
||||||
|
[positive? (lambda (v) 'positive)])
|
||||||
|
(raise n)))
|
||||||
|
(always-fail 2)
|
||||||
|
(always-fail 3)
|
||||||
|
(always-fail -3)
|
||||||
|
(with-handlers ([negative? (lambda (v) 'negative)])
|
||||||
|
(always-fail -3))
|
||||||
|
]
|
||||||
|
|
||||||
|
Using @scheme[(lambda (v) #t)] as a predicate captures all exceptions, of course:
|
||||||
|
|
||||||
|
@interaction[
|
||||||
|
(with-handlers ([(lambda (v) #t) (lambda (v) 'oops)])
|
||||||
|
(car 17))
|
||||||
|
]
|
||||||
|
|
||||||
|
Capturing all exceptions is usually a bad idea, however. If the user
|
||||||
|
types Ctl-C in a terminal window or clicks the @onscreen{Stop} button
|
||||||
|
in DrScheme to interrupt a computation, then normally the
|
||||||
|
@scheme[exn:break] exception should not be caught. To catch only
|
||||||
|
exceptions that represent errors, use @scheme[exn:fail?] as the
|
||||||
|
predicate:
|
||||||
|
|
||||||
|
@interaction[
|
||||||
|
(with-handlers ([exn:fail? (lambda (v) 'oops)])
|
||||||
|
(car 17))
|
||||||
|
(eval:alts ; `examples' doesn't catch break exceptions!
|
||||||
|
(with-handlers ([exn:fail? (lambda (v) 'oops)])
|
||||||
|
(break-thread (current-thread)) (code:comment #, @t{simulate Ctl-C})
|
||||||
|
(car 17))
|
||||||
|
(error "user break"))
|
||||||
|
]
|
||||||
|
|
||||||
|
@; ----------------------------------------
|
||||||
|
|
||||||
|
@section[#:tag "prompt"]{Prompts and Aborts}
|
||||||
|
|
||||||
|
When an exception is raised control, escapes out of an arbitrary deep
|
||||||
|
evaluation context to the point where the exception is caught---or all
|
||||||
|
the way out if the expression is never caught:
|
||||||
|
|
||||||
|
@interaction[
|
||||||
|
(+ 1 (+ 1 (+ 1 (+ 1 (+ 1 (+ 1 (/ 1 0)))))))
|
||||||
|
]
|
||||||
|
|
||||||
|
But if control escapes ``all the way out,'' why does the @tech{REPL}
|
||||||
|
keep going after an error is printed? You might think that it's
|
||||||
|
because the @tech{REPL} wraps every interaction in a
|
||||||
|
@scheme[with-handlers] form that catches all exceptions, but that's
|
||||||
|
not quite the reason.
|
||||||
|
|
||||||
|
The actual reason is that the @tech{REPL} wraps the interaction with a
|
||||||
|
@deftech{prompt}, which effectively marks the evaluation context with
|
||||||
|
an escape point. If an exception is not caught, then information about
|
||||||
|
the exception is printed, and then evaluation @deftech{aborts} to the
|
||||||
|
nearest enclosing prompt. More precisely, each prompt has a
|
||||||
|
@deftech{prompt tag}, and there is a designated @deftech{default
|
||||||
|
prompt tag} that the uncaught-exception handler uses to @tech{abort}.
|
||||||
|
|
||||||
|
The @scheme[call-with-continuation-prompt] function installs a prompt
|
||||||
|
with a given @tech{prompt tag}, and then it evaluates a given thunk
|
||||||
|
under the prompt. The @scheme[default-continuation-prompt-tag]
|
||||||
|
function returns the @tech{default prompt tag}. The
|
||||||
|
@scheme[abort-current-continuation] function escapes to the nearest
|
||||||
|
enclosing prompt that has a given @tech{prompt tag}.
|
||||||
|
|
||||||
|
@interaction[
|
||||||
|
(define (escape v)
|
||||||
|
(abort-current-continuation
|
||||||
|
(default-continuation-prompt-tag)
|
||||||
|
(lambda () v)))
|
||||||
|
(+ 1 (+ 1 (+ 1 (+ 1 (+ 1 (+ 1 (escape 0)))))))
|
||||||
|
(+ 1
|
||||||
|
(call-with-continuation-prompt
|
||||||
|
(lambda ()
|
||||||
|
(+ 1 (+ 1 (+ 1 (+ 1 (+ 1 (+ 1 (escape 0))))))))
|
||||||
|
(default-continuation-prompt-tag)))
|
||||||
|
]
|
||||||
|
|
||||||
|
In @scheme[escape] above, the value @scheme[v] is wrapped in a
|
||||||
|
procedure that is called after escaping to the enclosing prompt.
|
||||||
|
|
||||||
|
@tech{Prompts} and @tech{aborts} look very much like exception
|
||||||
|
handling and raising. Indeed, prompts and aborts are essentially a
|
||||||
|
more primitive form of exceptions, and @scheme[with-handlers] and
|
||||||
|
@scheme[raise] are implemented in terms of prompts and aborts. The
|
||||||
|
power of the more primitive forms is related to the word
|
||||||
|
``continuation'' in the operator names, as we discuss in the next
|
||||||
|
section.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section{Continuations}
|
||||||
|
|
||||||
|
|
||||||
|
A @deftech{continuation} is a value that encapsulates a piece of an
|
||||||
|
expression context. The @scheme[call-with-composable-continuation]
|
||||||
|
function captures the @deftech{current continuation} starting outside
|
||||||
|
function call an running up to the nearest enclosing prompt. (Keep in
|
||||||
|
mind that each @tech{REPL} interaction is implicitly wrapped in a
|
||||||
|
prompt.)
|
||||||
|
|
||||||
|
For example, in
|
||||||
|
|
||||||
|
@schemeblock[
|
||||||
|
(+ 1 (+ 1 (+ 1 0)))
|
||||||
|
]
|
||||||
|
|
||||||
|
at the point where @scheme[0] is evaluated, the expression context
|
||||||
|
includes three nested addition expressions. We can grab that context by
|
||||||
|
changing @scheme[0] to grab the continuation before returning 0:
|
||||||
|
|
||||||
|
@interaction[
|
||||||
|
#:eval cc-eval
|
||||||
|
(define saved-k #f)
|
||||||
|
(define (save-it!)
|
||||||
|
(call-with-composable-continuation
|
||||||
|
(lambda (k) (code:comment #, @t{@scheme[k] is the captured continuation})
|
||||||
|
(set! saved-k k)
|
||||||
|
0)))
|
||||||
|
(+ 1 (+ 1 (+ 1 (save-it!))))
|
||||||
|
]
|
||||||
|
|
||||||
|
The @tech{continuation} saved in @scheme[save-k] encapsulates the
|
||||||
|
program context @scheme[(+ 1 (+ 1 (+ 1 _?)))], where @scheme[_?]
|
||||||
|
represents a place to plug in a result value---because that was the
|
||||||
|
expression context when @scheme[save-it!] was called. The
|
||||||
|
@tech{continuation} is encapsulated so that it behaves like the
|
||||||
|
function @scheme[(lambda (v) (+ 1 (+ 1 (+ 1 v))))]:
|
||||||
|
|
||||||
|
@interaction[
|
||||||
|
#:eval cc-eval
|
||||||
|
(saved-k 0)
|
||||||
|
(saved-k 10)
|
||||||
|
(saved-k (saved-k 0))
|
||||||
|
]
|
||||||
|
|
||||||
|
The continuation captured by
|
||||||
|
@scheme[call-with-composable-continuation] is determined dynamically,
|
||||||
|
not syntactically. For example, with
|
||||||
|
|
||||||
|
@interaction[
|
||||||
|
#:eval cc-eval
|
||||||
|
(define (sum n)
|
||||||
|
(if (zero? n)
|
||||||
|
(save-it!)
|
||||||
|
(+ n (sum (sub1 n)))))
|
||||||
|
(sum 5)
|
||||||
|
]
|
||||||
|
|
||||||
|
the continuation in @scheme[saved-k] becomes @scheme[(lambda (x) (+ 5
|
||||||
|
(+ 4 (+ 3 (+ 2 (+ 1 x))))))]:
|
||||||
|
|
||||||
|
@interaction[
|
||||||
|
#:eval cc-eval
|
||||||
|
(saved-k 0)
|
||||||
|
(saved-k 10)
|
||||||
|
]
|
||||||
|
|
||||||
|
A more traditional continuation operator in Scheme is
|
||||||
|
@scheme[call-with-current-continuation], which is often abbreviated
|
||||||
|
@scheme[call/cc]. It is like
|
||||||
|
@scheme[call-with-composable-continuation], but applying the captured
|
||||||
|
continuation first @tech{aborts} (to the current @tech{prompt}) before
|
||||||
|
restoring the saved continuation. In addition, Scheme systems
|
||||||
|
traditionally support a single prompt at the program start, instead of
|
||||||
|
allowing new prompts via
|
||||||
|
@scheme[call-with-continuation-prompt]. Continuations as in PLT Scheme
|
||||||
|
are sometimes called @deftech{delimited continuations}, since a
|
||||||
|
program can introduce new delimiting prompts, and continuations as
|
||||||
|
captured by @scheme[call-with-composable-continuation] are sometimes
|
||||||
|
called @deftech{composable continuations}, because they do not have a
|
||||||
|
built-in @tech{abort}.
|
||||||
|
|
||||||
|
For an example of how @tech{continuations} are useful, see
|
||||||
|
@other-manual['(lib "scribblings/more/more.scrbl")]. For specific
|
||||||
|
control operators that have more convenient names than the primitives
|
||||||
|
described here, see @schememodname[scheme/control].
|
|
@ -36,17 +36,12 @@ precise details to @|MzScheme| and other reference manuals.
|
||||||
|
|
||||||
@include-section["regexp.scrbl"]
|
@include-section["regexp.scrbl"]
|
||||||
|
|
||||||
@; ----------------------------------------------------------------------
|
@include-section["control.scrbl"]
|
||||||
@section[#:tag "control"]{Exceptions and Control}
|
|
||||||
|
|
||||||
@; ----------------------------------------------------------------------
|
|
||||||
@include-section["for.scrbl"]
|
@include-section["for.scrbl"]
|
||||||
|
|
||||||
|
|
||||||
@; ----------------------------------------------------------------------
|
|
||||||
@include-section["match.scrbl"]
|
@include-section["match.scrbl"]
|
||||||
|
|
||||||
@; ----------------------------------------------------------------------
|
|
||||||
@include-section["class.scrbl"]
|
@include-section["class.scrbl"]
|
||||||
|
|
||||||
@; ----------------------------------------------------------------------
|
@; ----------------------------------------------------------------------
|
||||||
|
@ -145,7 +140,12 @@ downloadable packages contributed by PLT Scheme users.
|
||||||
#:title "Scheme with Classes, Mixins, and Traits (invited tutorial)"
|
#:title "Scheme with Classes, Mixins, and Traits (invited tutorial)"
|
||||||
#:location "Asian Symposium on Programming Languages and Systems"
|
#:location "Asian Symposium on Programming Languages and Systems"
|
||||||
#:date "2006")
|
#:date "2006")
|
||||||
|
|
||||||
|
(bib-entry #:key "Mitchell02"
|
||||||
|
#:author "Richard Mitchell and Jim McKim"
|
||||||
|
#:title "Design by Contract, by Example"
|
||||||
|
#:is-book? #t
|
||||||
|
#:date "2002")
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,119 @@
|
||||||
"guide-utils.ss"
|
"guide-utils.ss"
|
||||||
(for-label scheme/match))
|
(for-label scheme/match))
|
||||||
|
|
||||||
|
@(begin
|
||||||
|
(define match-eval (make-base-eval))
|
||||||
|
(interaction-eval #:eval match-eval (require scheme/match)))
|
||||||
|
|
||||||
@title[#:tag "match"]{Pattern Matching}
|
@title[#:tag "match"]{Pattern Matching}
|
||||||
|
|
||||||
The @scheme[match] form supports pattern matching on arbitrary Scheme
|
The @scheme[match] form supports pattern matching on arbitrary Scheme
|
||||||
values, as opposed to functions like @scheme[regexp-match] that
|
values, as opposed to functions like @scheme[regexp-match] that
|
||||||
compare regular expressions to byte and character sequences (see
|
compare regular expressions to byte and character sequences (see
|
||||||
@secref["regexp"]).
|
@secref["regexp"]).
|
||||||
|
|
||||||
|
@specform[
|
||||||
|
(match target-expr
|
||||||
|
[pattern expr ...+] ...)
|
||||||
|
]
|
||||||
|
|
||||||
|
The @scheme[match] form takes the result of @scheme[target-expr] and
|
||||||
|
tries to match each @scheme[_pattern] in order. As soon as it finds a
|
||||||
|
match, it evaluates the corresponding @scheme[_expr] sequence to
|
||||||
|
obtain the result for the @scheme[match] form. If @scheme[_pattern]
|
||||||
|
includes @deftech{pattern variables}, they are treated like wildcards,
|
||||||
|
and each variable is bound in the @scheme[_expr] to the input
|
||||||
|
fragments that it matched.
|
||||||
|
|
||||||
|
Most Scheme literal expressions can be used as patterns:
|
||||||
|
|
||||||
|
@interaction[
|
||||||
|
#:eval match-eval
|
||||||
|
(match 2
|
||||||
|
[1 'one]
|
||||||
|
[2 'two]
|
||||||
|
[3 'three])
|
||||||
|
(match #f
|
||||||
|
[#t 'yes]
|
||||||
|
[#f 'no])
|
||||||
|
(match "apple"
|
||||||
|
['apple 'symbol]
|
||||||
|
["apple" 'string]
|
||||||
|
[#f 'boolean])
|
||||||
|
]
|
||||||
|
|
||||||
|
Constructors like @scheme[cons], @scheme[list], and @scheme[vector]
|
||||||
|
can be used to create patterns that match pairs, lists, and vectors:
|
||||||
|
|
||||||
|
@interaction[
|
||||||
|
#:eval match-eval
|
||||||
|
(match '(1 2)
|
||||||
|
[(list 0 1) 'one]
|
||||||
|
[(list 1 2) 'two])
|
||||||
|
(match '(1 . 2)
|
||||||
|
[(list 1 2) 'list]
|
||||||
|
[(cons 1 2) 'pair])
|
||||||
|
(match #(1 2)
|
||||||
|
[(list 1 2) 'list]
|
||||||
|
[(vector 1 2) 'vector])
|
||||||
|
]
|
||||||
|
|
||||||
|
The @scheme[struct] construct matches an instance of a particular
|
||||||
|
structure type:
|
||||||
|
|
||||||
|
@interaction[
|
||||||
|
#:eval match-eval
|
||||||
|
(define-struct shoe (size color))
|
||||||
|
(define-struct hat (size style))
|
||||||
|
(match (make-hat 23 'bowler)
|
||||||
|
[(struct shoe (10 'white)) "bottom"]
|
||||||
|
[(struct hat (23 'bowler)) "top"])
|
||||||
|
]
|
||||||
|
|
||||||
|
Unquoted, non-constructor identifiers in an pattern are @tech{pattern
|
||||||
|
variables} that are bound in the result expressions:
|
||||||
|
|
||||||
|
@interaction[
|
||||||
|
#:eval match-eval
|
||||||
|
(match '(1)
|
||||||
|
[(list x) (+ x 1)]
|
||||||
|
[(list x y) (+ x y)])
|
||||||
|
(match '(1 2)
|
||||||
|
[(list x) (+ x 1)]
|
||||||
|
[(list x y) (+ x y)])
|
||||||
|
(match (make-hat 23 'bowler)
|
||||||
|
[(struct shoe (sz col)) sz]
|
||||||
|
[(struct hat (sz stl)) sz])
|
||||||
|
]
|
||||||
|
|
||||||
|
An ellipsis, written @litchar{...}, act like a Kleene star within a
|
||||||
|
list or vector pattern: the preceding sub-pattern can be used to match
|
||||||
|
any number of times for any number of consecutive elements of the list
|
||||||
|
of vector. If a sub-pattern followed by an ellipsis includes a pattern
|
||||||
|
variable, the variable matches multiple times, and it is bound in the
|
||||||
|
result expression to a list of matches:
|
||||||
|
|
||||||
|
@interaction[
|
||||||
|
#:eval match-eval
|
||||||
|
(match '(1 1 1)
|
||||||
|
[(list 1 ...) 'ones]
|
||||||
|
[else 'other])
|
||||||
|
(match '(1 1 2)
|
||||||
|
[(list 1 ...) 'ones]
|
||||||
|
[else 'other])
|
||||||
|
(match '(1 2 3 4)
|
||||||
|
[(list 1 x ... 4) x])
|
||||||
|
(match (list (make-hat 23 'bowler) (make-hat 22 'pork-pie))
|
||||||
|
[(list (struct hat (sz styl)) ...) (apply + sz)])
|
||||||
|
]
|
||||||
|
|
||||||
|
Ellipses can be nested to match nested repetitions, and in that case,
|
||||||
|
pattern variables can be bound to lists of lists of matches:
|
||||||
|
|
||||||
|
@interaction[
|
||||||
|
#:eval match-eval
|
||||||
|
(match '((! 1) (! 2 2) (! 3 3 3))
|
||||||
|
[(list (list '! x ...) ...) x])
|
||||||
|
]
|
||||||
|
|
||||||
|
For information on many more pattern forms, see @schememodname[scheme/match].
|
||||||
|
|
|
@ -928,6 +928,7 @@ order as given}
|
||||||
|
|
||||||
@defproc[(bib-entry [#:key key string?]
|
@defproc[(bib-entry [#:key key string?]
|
||||||
[#:title title any/c]
|
[#:title title any/c]
|
||||||
|
[#:is-book? is-book? any/c #f]
|
||||||
[#:author author any/c]
|
[#:author author any/c]
|
||||||
[#:location location any/c]
|
[#:location location any/c]
|
||||||
[#:date date any/c]
|
[#:date date any/c]
|
||||||
|
@ -941,7 +942,8 @@ the entry:
|
||||||
@itemize{
|
@itemize{
|
||||||
|
|
||||||
@item{@scheme[title] is the title of the cited work. It will be
|
@item{@scheme[title] is the title of the cited work. It will be
|
||||||
surrounded by quotes in typeset form.}
|
surrounded by quotes in typeset form if @scheme[is-book?] is
|
||||||
|
@scheme[#f], otherwise it is typeset via @scheme[italic].}
|
||||||
|
|
||||||
@item{@scheme[author] lists the authors. Use names in their usual
|
@item{@scheme[author] lists the authors. Use names in their usual
|
||||||
order (as opposed to ``last, first''), and separate multiple
|
order (as opposed to ``last, first''), and separate multiple
|
||||||
|
|
Loading…
Reference in New Issue
Block a user