fill in some guide sections

svn: r9871
This commit is contained in:
Matthew Flatt 2008-05-16 21:23:53 +00:00
parent 61a80e85fb
commit 2b48cb0a4d
13 changed files with 451 additions and 59 deletions

View File

@ -356,6 +356,8 @@
;; Like a toplevel (eval `(begin ,@exprs)), but the language that is used may
;; not have a begin.
(define (eval* exprs)
(call-with-continuation-prompt
(lambda ()
(if (null? exprs)
(void)
(let ([deftag (default-continuation-prompt-tag)])
@ -367,7 +369,7 @@
(lambda () (eval expr))
deftag
(lambda (x) (abort-current-continuation deftag x)))
(loop (car exprs) (cdr exprs))))))))
(loop (car exprs) (cdr exprs))))))))))
(define (evaluate-program program limits uncovered!)
(when uncovered!

View File

@ -144,8 +144,12 @@
(loop (extract s cdr car)
(list (syntax->datum (datum->syntax #f (extract s cdr cdr car)))))]
[else
(let ([r (with-handlers ([exn:fail? (lambda (e)
(list (exn-message e)
(let ([r (with-handlers ([(lambda (x)
(not (exn:break? x)))
(lambda (e)
(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)])

View File

@ -2042,6 +2042,7 @@
(define (bib-entry #:key key
#:title title
#:is-book? [is-book? #f]
#:author [author #f]
#:location [location #f]
#:date [date #f]
@ -2055,12 +2056,19 @@
(append (decode-content (list author))
(list ", "))
null)
(list 'ldquo)
(decode-content (list title))
(if is-book?
null
(list 'ldquo))
(if is-book?
(list (italic title))
(decode-content (list title)))
(list (if location
","
".")
'rdquo)
"."))
(if is-book?
null
(list 'rdquo))
(if location
(cons " "
(append

View File

@ -6,18 +6,18 @@
(for-label scheme/contract)
(for-label scheme/gui))
@title{Examples}
@title[#:tag "contracts-examples"]{Examples}
This section illustrates the current state of PLT Scheme's contract
implementation with a series of examples from Mitchell and McKim's text
book "Design by Contract, by Example" [Addison and Wesley, 2002].
implementation with a series of examples from @italic{Design by
Contract, by Example} @cite["Mitchell02"].
Mitchell and McKim's principles for design by contract DbC are derived
from the 1970s style algebraic specifications. The overall goal of DbC is
to specify the constructors of an algebra in terms of its
observers. While we reformulate Mitchell and McKim's terminology and
we use a mostly applicative, we
retain their terminology of "classes" and "objects":
retain their terminology of ``classes'' and ``objects'':
@itemize{
@item{@bold{Separate queries from commands.}

View File

@ -7,9 +7,9 @@
(for-label scheme/contract)
(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
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
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
@link["http://schemecookbook.org"]{Scheme cookbook}:
@ -121,7 +121,7 @@ arguments: @scheme[char?]. }
yourself, you need to communicate across boundaries for
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
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
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
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
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
@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
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:
@ -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
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
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
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
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.
}
@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
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.
@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
function and a list of numbers that eventually applies the former to the

View File

@ -5,9 +5,9 @@
"contracts-utils.ss"
(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
@scheme[provide/contract] are not assigned to, but does not enforce

View File

@ -47,7 +47,7 @@ scheme/base
(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
@schememod[
@ -62,7 +62,7 @@ When module @scheme[a] is required, the monitoring
system signals a violation of the contract and
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
@schememod[
@ -184,7 +184,7 @@ the module boundary for a second time.
</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
another module only if the other module abides by certain

View File

@ -18,7 +18,7 @@ value back to the ``client'' module.
It is important to keep this picture in mind when you read the explanations
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
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
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
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
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
@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].
@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
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?)]
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:
@ -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
@scheme[any] is a keyword that can appear in the range of

View File

@ -5,7 +5,7 @@
"contracts-utils.ss"
(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
@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
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
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
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
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
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
@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
check the fields of the data structure, but sometimes this

View 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].

View File

@ -36,17 +36,12 @@ precise details to @|MzScheme| and other reference manuals.
@include-section["regexp.scrbl"]
@; ----------------------------------------------------------------------
@section[#:tag "control"]{Exceptions and Control}
@include-section["control.scrbl"]
@; ----------------------------------------------------------------------
@include-section["for.scrbl"]
@; ----------------------------------------------------------------------
@include-section["match.scrbl"]
@; ----------------------------------------------------------------------
@include-section["class.scrbl"]
@; ----------------------------------------------------------------------
@ -146,6 +141,11 @@ downloadable packages contributed by PLT Scheme users.
#:location "Asian Symposium on Programming Languages and Systems"
#:date "2006")
(bib-entry #:key "Mitchell02"
#:author "Richard Mitchell and Jim McKim"
#:title "Design by Contract, by Example"
#:is-book? #t
#:date "2002")
)

View File

@ -4,9 +4,119 @@
"guide-utils.ss"
(for-label scheme/match))
@(begin
(define match-eval (make-base-eval))
(interaction-eval #:eval match-eval (require scheme/match)))
@title[#:tag "match"]{Pattern Matching}
The @scheme[match] form supports pattern matching on arbitrary Scheme
values, as opposed to functions like @scheme[regexp-match] that
compare regular expressions to byte and character sequences (see
@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].

View File

@ -928,6 +928,7 @@ order as given}
@defproc[(bib-entry [#:key key string?]
[#:title title any/c]
[#:is-book? is-book? any/c #f]
[#:author author any/c]
[#:location location any/c]
[#:date date any/c]
@ -941,7 +942,8 @@ the entry:
@itemize{
@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
order (as opposed to ``last, first''), and separate multiple