guide and reference work; change opt-lambda to use lambda/kw and hack in keyword support for documentation purposes, along with define-opt

svn: r6572
This commit is contained in:
Matthew Flatt 2007-06-11 07:19:42 +00:00
parent 0d69b92c79
commit 32e9101594
38 changed files with 971 additions and 438 deletions

View File

@ -1,7 +1,8 @@
(module etc mzscheme
(require (lib "main-collects.ss" "setup"))
(require (lib "main-collects.ss" "setup")
"kw.ss")
(require-for-syntax (lib "kerncase.ss" "syntax")
(lib "stx.ss" "syntax")
@ -23,6 +24,7 @@
loop-until
opt-lambda
define-opt
local
recur
@ -129,52 +131,82 @@
(eq? x y))
(define-syntax (opt-lambda stx)
(with-syntax ([name (or (syntax-local-infer-name stx)
(quote-syntax opt-lambda-proc))])
(syntax-case stx ()
[(_ args body1 body ...)
(let ([clauses (let loop ([pre-args null]
[args (syntax args)]
[needs-default? #f])
(syntax-case args ()
[id
(identifier? (syntax id))
(with-syntax ([(pre-arg ...) pre-args])
(syntax ([(pre-arg ... . id)
body1 body ...])))]
[()
(with-syntax ([(pre-arg ...) pre-args])
(syntax ([(pre-arg ...)
body1 body ...])))]
[(id . rest)
(identifier? (syntax id))
(begin
(when needs-default?
(raise-syntax-error
#f "default value missing" stx (syntax id)))
(loop (append pre-args (list (syntax id)))
(syntax rest)
#f))]
[([id default] . rest)
(identifier? (syntax id))
(with-syntax ([rest (loop (append pre-args (list (syntax id)))
(syntax rest)
#t)]
[(pre-arg ...) pre-args])
(syntax ([(pre-arg ...) (name pre-arg ... default)]
. rest)))]
[(bad . rest)
(raise-syntax-error
#f
"not an identifier or identifier with default"
stx
(syntax bad))]
[else
(raise-syntax-error
#f "bad identifier sequence" stx (syntax args))]))])
(with-syntax ([clauses clauses])
(syntax/loc stx
(letrec ([name (case-lambda . clauses)]) name))))])))
(syntax-case stx ()
[(_ args body1 body ...)
(with-syntax ([((plain ...) (opt ...) (kw ...) need-kw rest)
(let loop ([args (syntax args)]
[needs-default? #f])
(syntax-case args ()
[id
(identifier? (syntax id))
#'(() () () () (#:body id))]
[()
#'(() () () () ())]
[(id . rest)
(identifier? (syntax id))
(begin
(when needs-default?
(raise-syntax-error
#f "default value missing" stx (syntax id)))
(with-syntax ([(plain opts kws need-kw rest) (loop #'rest #f)])
#'((id . plain) opts kws need-kw rest)))]
[([id default] . rest)
(identifier? (syntax id))
(with-syntax ([(plain opts kws need-kw rest) (loop #'rest #t)])
#'(plain ([id default] . opts) kws need-kw rest))]
[(kw id . rest)
(and (identifier? #'id)
(keyword? (syntax-e #'kw)))
(with-syntax ([(plain opts kws need-kw rest) (loop #'rest needs-default?)])
#'(plain opts ([id kw #f] . kws) (kw . need-kw) rest))]
[(kw [id default] . rest)
(and (identifier? #'id)
(keyword? (syntax-e #'kw)))
(with-syntax ([(plain opts kws need-kw rest) (loop #'rest needs-default?)])
#'(plain opts ([id kw default] . kws) need-kw rest))]
[(bad . rest)
(raise-syntax-error
#f
"not an identifier or identifier with default"
stx
(syntax bad))]
[else
(raise-syntax-error
#f "bad identifier sequence" stx (syntax args))]))])
(let ([kw-proc (syntax/loc stx
(lambda/kw [plain ... #:optional opt ... #:key kw ... . rest] body1 body ...))])
(if (null? (syntax-e #'(kw ...)))
kw-proc
(with-syntax ([name (or (syntax-local-infer-name stx)
(quote-syntax opt-lambda-proc))]
[kw-proc kw-proc]
[len (length (syntax->list #'(plain ...)))])
(syntax/loc stx
(let ([name kw-proc])
(lambda all-args
(apply name (sort-kws len 'need-kw all-args)))))))))]))
(define-syntax define-opt
(syntax-rules ()
[(_ (id . args) body1 body ...)
(define id (opt-lambda args body1 body ...))]
[(_ . rest) (define . rest)]))
(define (sort-kws len need-kw l)
(for-each (lambda (kw)
(unless (memq kw l)
(error "missing required argument for" kw)))
need-kw)
(let loop ([len len][l l][kws null])
(cond
[(null? l) (append kws l)]
[(zero? len) (append kws l)]
[(and (keyword? (car l))
(pair? (cdr l)))
(loop len (cddr l) (list* (car l)
(cadr l)
kws))]
[else (cons (car l) (loop (sub1 len) (cdr l) kws))])))
(define-syntax (local stx)
(syntax-case stx ()

View File

@ -8,6 +8,8 @@
for/or for*/or
for/first for*/first
for/last for*/last
for/fold/derived for*/fold/derived
(rename *in-range in-range)
(rename *in-naturals in-naturals)

View File

@ -210,9 +210,9 @@
[(_ (eval:alts a b)) (schemeinput* a)]
[(_ e) (schemeinput e)]))
(define (defspace p)
(make-flow (list p
(make-paragraph null))))
(define-code schemeblock+line (to-paragraph/prefix (hspace 2)
(hspace 2)
(list " ")))
(define-syntax (schemedefinput* stx)
(syntax-case stx (eval-example-string define define-struct)
@ -220,13 +220,13 @@
#'(schemeinput* (eval-example-string s))]
[(_ (define . rest))
(syntax-case stx ()
[(_ e) #'(defspace (schemeblock e))])]
[(_ e) #'(schemeblock+line e)])]
[(_ (define-struct . rest))
(syntax-case stx ()
[(_ e) #'(defspace (schemeblock e))])]
[(_ e) #'(schemeblock+line e)])]
[(_ (code:line (define . rest) . rest2))
(syntax-case stx ()
[(_ e) #'(defspace (schemeblock e))])]
[(_ e) #'(schemeblock+line e)])]
[(_ e) #'(schemeinput e)]))
(define-syntax titled-interaction

View File

@ -75,7 +75,7 @@
(pair? number))
(printf "\\~a~a{"
(case (length number)
[(0 1) "section"]
[(0 1) "newpage\n\n\\section"]
[(2) "subsection"]
[(3) "subsubsection"]
[else "subsubsection*"])

View File

@ -150,7 +150,8 @@
;; ----------------------------------------
(provide defproc defproc* defstruct defthing defform defform* defform/subs defform*/subs defform/none
specform specsubform specsubform/inline
specform specform/subs
specsubform specspecsubform specsubform/inline
schemegrammar
var svar void-const undefined-const)
@ -250,15 +251,30 @@
(define-syntax specsubform
(syntax-rules ()
[(_ spec desc ...)
(*specsubform 'spec #f (lambda () (schemeblock0 spec)) (lambda () (list desc ...)))]))
(*specsubform 'spec #f (lambda () (schemeblock0 spec)) null null (lambda () (list desc ...)))]))
(define-syntax specspecsubform
(syntax-rules ()
[(_ spec desc ...)
(make-blockquote "leftindent" (list (specsubform spec desc ...)))]))
(define-syntax specform
(syntax-rules ()
[(_ spec desc ...)
(*specsubform 'spec #t (lambda () (schemeblock0 spec)) (lambda () (list desc ...)))]))
(*specsubform 'spec #t (lambda () (schemeblock0 spec)) null null (lambda () (list desc ...)))]))
(define-syntax specform/subs
(syntax-rules ()
[(_ spec ([non-term-id non-term-form ...] ...) desc ...)
(*specsubform 'spec #t
(lambda () (schemeblock0 spec))
'((non-term-id non-term-form ...) ...)
(list (list (lambda () (scheme non-term-id))
(lambda () (schemeblock0 non-term-form))
...)
...)
(lambda () (list desc ...)))]))
(define-syntax specsubform/inline
(syntax-rules ()
[(_ spec desc ...)
(*specsubform 'spec #f #f (lambda () (list desc ...)))]))
(*specsubform 'spec #f #f null null (lambda () (list desc ...)))]))
(define-syntax defthing
(syntax-rules ()
[(_ id result desc ...)
@ -523,9 +539,10 @@
sub-procs))))
(content-thunk)))))
(define (*specsubform form has-kw? form-thunk content-thunk)
(define (*specsubform form has-kw? form-thunk subs sub-procs content-thunk)
(parameterize ([current-variable-list
(append (let loop ([form (if has-kw? (cdr form) form)])
(append (let loop ([form (cons (if has-kw? (cdr form) form)
subs)])
(cond
[(symbol? form) (if (meta-symbol? form)
null
@ -539,12 +556,20 @@
(cons
(make-table
'boxed
(list (list
(make-flow
(list
(if form-thunk
(form-thunk)
(make-paragraph (list (to-element form)))))))))
(cons
(list
(make-flow
(list
(if form-thunk
(form-thunk)
(make-paragraph (list (to-element form)))))))
(apply
append
(map (lambda (sub)
(list (list (make-flow (list (make-paragraph (list (tt 'nbsp))))))
(list (make-flow (list (apply *schemerawgrammar
(map (lambda (f) (f)) sub)))))))
sub-procs))))
(flow-paragraphs (decode-flow (content-thunk)))))))
(define (*schemerawgrammar nonterm clause1 . clauses)
@ -643,5 +668,29 @@
[else (list i)])))
c)))))
;; ----------------------------------------
(provide cite)
(define/kw (cite #:key key title author location date)
"[...]"
#;
(make-bibliography-element
#f
(list "[...]")
key
(list (string-append
(content->string (list author))
", "
(content->string (list title))))
(list (make-element #f (list author
", "
title
", "
date
". "
location
".")))))
;; ----------------------------------------
)

View File

@ -369,7 +369,6 @@
(string? (syntax-e c))
(bytes? (syntax-e c))
(char? (syntax-e c))
(keyword? (syntax-e c))
(boolean? (syntax-e c)))
value-color]
[(identifier? c)
@ -389,7 +388,12 @@
(set! dest-col 0)
(hash-table-put! next-col-map init-col dest-col)
((loop (lambda () (set! src-col init-col) (set! dest-col 0)) 0) c)
(out suffix #f)
(if (list? suffix)
(map (lambda (sfx)
(finish-line!)
(out sfx #f))
suffix)
(out suffix #f))
(unless (null? content)
(finish-line!))
(if multi-line?

View File

@ -12,19 +12,19 @@ An expression of the form
]
is a procedure application when @scheme[_proc-expr] is not an
identifier that is bound as a transformer. The @scheme[...] in this
syntactic sketch means ``zero or more repetitions of the preceding
element.'' Specifically, it means zero or more @scheme[_arg-expr]s.
identifier that is bound as a transformer.
@section{Evaluation Order and Arity}
A procedure application is evaluated by first evaluating the
@scheme[_proc-expr] and all @scheme[_arg-expr]s in order (left to
right). Then, if @scheme[_proc-expr] produced a procedure that accepts
as many arguments as supplied @scheme[_arg-expr]s, the procedure is
aplied. Otherwise, an exception is raised.
applied. Otherwise, an exception is raised.
@examples[
(cons 1 null)
((lambda (x y z) (+ x y z)) 1 2 3)
(+ 1 2 3)
(cons 1 2 3)
(1 2 3)
]
@ -32,19 +32,80 @@ aplied. Otherwise, an exception is raised.
Some procedures, such as @scheme[cons], accept a fixed number of
arguments. Some procedures, such as @scheme[list], accept any number
of arguments. Some procedures accept a range of argument counts; for
example @scheme[substring] accepts either two or three arguments.
example @scheme[substring] accepts either two or three arguments. A
procedure's @idefterm{arity} is the number(s) of arguments that it
accepts.
@;------------------------------------------------------------------------
@section{Keyword Arguments}
Some procedures accept @defterm{keyword arguments} in addition to
by-position arguments. To supply a keyword argument, include a keyword
followed by the addociated argument value. The order of keyword
arguments does not matter, nor does their position relative to
non-keyword arguments (as long as they follow the procedure
expression); keyword arguments are recognized by an applied procedure
using only the associated keyword, not the order.
by-position arguments. For that case, an @scheme[_arg] can be an
@scheme[_arg-keyword _arg-expr] sequence instead of just a
@scheme[_arg-expr]:
@examples[
(need-an-example 1 #:arg 2)
(need-an-example #:arg 2 1)
@specform/subs[
(_proc-expr _arg ...)
([arg arg-expr
(code:line arg-keyword arg-expr)])
]
For example,
@schemeblock[(go "super.ss" #:mode 'fast)]
calls the procedure bound to @scheme[go] with @scheme["super.ss"] as a
by-position argument, and with @scheme['fast] as an argument associated
with the @scheme[#:mode] keyword. Thus, a keyword is implicitly paired
with the expression that follows it. Since a keyword by itself is not
an expression, then
@schemeblock[(go "super.ss" #:mode #:fast)]
is a syntax error---because @scheme[#:fast] is not an expression.
The order of keyword @scheme[_arg]s determines the order in which
@scheme[_arg-expr]s are evaluated, but a procedure accepts (or
declines) keyword arguments independent of their position in the
argument list. That is, keyword arguments are recognized by an applied
procedure using only the associated keyword. The above call to
@scheme[go] can be equivalently written
@schemeblock[(go #:mode #:fast "super.ss")]
@refdetails["mz:application"]{procedure applications}
@;------------------------------------------------------------------------
@section[#:tag "guide:apply"]{The @scheme[apply] Procedure}
The syntax for procedure applications supports any number of
arguments, but a specific application expression always specifies a
fixed number of arguments. As a result, a procedure that takes a list
of arguments cannot directly apply a procedure like @scheme[+] to all
of the items in the list:
@def+int[
(define (avg lst) (code:comment #, @elem{doesn't work...})
(/ (+ lst) (length lst)))
(avg '(1 2 3))
]
@def+int[
(define (avg lst) (code:comment #, @elem{doesn't always work...})
(/ (+ (list-ref lst 0) (list-ref lst 1) (list-ref lst 2))
(length lst)))
(avg '(1 2 3))
(avg '(1 2))
]
The @scheme[apply] procedure offers a way around this restriction, It
takes another procedure a @italic{list} arguments, and it applies the
procedure to the arguments:
@def+int[
(define (avg lst)
(/ (apply + lst) (length lst)))
(avg '(1 2 3))
(avg '(1 2))
(avg '(1 2 3 4))
]

View File

@ -23,7 +23,7 @@ prints like the ASCII decoding of the byte string, but prefixed with a
@litchar{#}. Unprintable ASCII characters or non-ASCII bytes in the
byte string are written with octal notation.
@refdetails["mz:parse-string"]{the syntax of byte strings}
@refdetails/gory["mz:parse-string"]{the syntax of byte strings}
@examples[
#"Apple"
@ -37,7 +37,7 @@ b
]
The @scheme[display] form of a byte string writes its raw bytes to the
current output port (see @secref["output"]). Technically,
current output port (see @secref["guide:i/o"]). Technically,
@scheme[display] of a normal (i.e,. character) string prints the UTF-8
encoding of the string to the current output port, since output is
ultimately defined in terms of bytes; @scheme[display] of a byte

View File

@ -15,10 +15,10 @@ to three octal digits, and hexadimal escapes with @litchar["\\u"]
(up to four digits). Unprintable characters in a string normally
shown with @litchar["\\u"] when the string is printed.
@refdetails["mz:parse-string"]{the syntax of strings}
@refdetails/gory["mz:parse-string"]{the syntax of strings}
The @scheme[display] procedure directly writes the characters of a
string to the current output port (see @secref["output"]), in contrast
string to the current output port (see @secref["guide:i/o"]), in contrast
to the string-constant syntax used to print a string result.
@examples[

View File

@ -26,7 +26,7 @@ number. A few characters are printed specially; for example, the space
and linefeed characters print as @scheme[#\space] and
@scheme[#\newline], respectively.
@refdetails["mz:parse-character"]{the syntax of characters}
@refdetails/gory["mz:parse-character"]{the syntax of characters}
@examples[
(integer->char 65)
@ -38,7 +38,7 @@ and linefeed characters print as @scheme[#\space] and
]
The @scheme[display] procedure directly writes a character to the
current output port (see @secref["output"]), in contrast to the
current output port (see @secref["guide:i/o"]), in contrast to the
character-constant syntax used to print a character result.
@examples[

View File

@ -17,9 +17,9 @@ objects to @secref["classes"].
To a first approximation, the syntax of @scheme[define-struct] is
@schemeblock[
(define-struct _struct-id (_field-id ...))
]
@specform[
(define-struct struct-id (field-id ...))
]{}
Such a definition binds @scheme[_struct-id], but only to static
information about the structure type that cannot be used directly:
@ -71,13 +71,13 @@ are built from @scheme[_struct-id] and the @scheme[_field-id]s:
}
A @scheme[define-struct] form places no constraints on the kinds of
values that can appears for fields in an instance of the structure
values that can appear for fields in an instance of the structure
type. For example, @scheme[(make-posn "apple" #f)] produces an
instance of @scheme[posn], even though @scheme["apple"] and
@scheme[#f] are not valid co-ordinates for the obvious uses of
@scheme[#f] are not valid coordinates for the obvious uses of
@scheme[posn] instances. Enforcing constraints on field values, such
as requiring them to be numbers, is the job of a contract, as
discussed later in @secref["contracts"].
discussed later in @secref["guide:contracts"].
@; ------------------------------------------------------------
@section{Structure Subtypes}
@ -86,8 +86,8 @@ An extended form of @scheme[defin-struct] can be used to define a
@defterm{structure subtype}, which is a structure type that extends an
existing structure type:
@schemeblock[
(define-struct (_struct-id _super-id) (_field-id ...))
@specform[
(define-struct (struct-id super-id) (field-id ...))
]
The @scheme[_super-id] must be a structure type name bound by
@ -133,13 +133,19 @@ To make a structure type @defterm{transparent}, use the
field-name sequence:
@def+int[
(define-struct posn (x y)
#f)
'(define-struct posn (x y)
#:inspector #f)
(make-posn 1 2)
]
An instance of a transparent structure type prints like a vector, and
it shows the content of the structure's fields. A transparent
structure type allows allows reflective operations like
@scheme[struct?] and @scheme[struct-info] to be used on its
structure type also allows reflective operations, like
@scheme[struct?] and @scheme[struct-info], to be used on its
instances (see @secref["reflection"]).
Structure types are opaque by default, because opaque structure
instances provide more encapsulation guarantees. That is, a library
can use an opaque structure to encapsulate data, and clients of the
library cannot manipulate the data in the structure except as allowed
by the library.

View File

@ -3,8 +3,117 @@
@require[(lib "eval.ss" "scribble")]
@require["guide-utils.ss"]
@interaction-eval[(require (rename (lib "etc.ss") define define-opt))]
@title{Definitions: @scheme[define] and @scheme[define-values]}
A definition can have the form
A basic definition has the form
@specform[(define _id _expr)]
@specform[(define id expr)]{}
in which case @scheme[_id] is bound to the result of
@scheme[_expr].
@defexamples[
(define salutation (list-ref '("Hi" "Hello") (random 2)))
salutation
]
@;------------------------------------------------------------------------
@section{Procedure Shorthand}
The @scheme[define] form also supports a shorthand for procedure
definitions:
@specform[(define (id arg ...) body ...+)]{}
which is a shorthand for
@schemeblock[
(define id (lambda (arg ...) _body ...+))
]
@defexamples[
(define (greet name)
(string-append salutation ", " name))
(greet "John")
]
@def+int[
(define (greet first [surname "Smith"] #:hi [hi salutation])
(string-append hi ", " first " " surname))
(greet "John")
(greet "John" #:hi "Hey")
(greet "John" "Doe")
]
The procedure shorthand via @scheme[define] also supports a final
argument to collect extra arguments in a list:
@specform[(define (id arg ... . rest-id) expr)]{}
which is a shorthand
@schemeblock[
(define id (lambda (id arg ... . rest-id) body-expr ...+))
]
@defexamples[
(define (avg . l)
(/ (apply + l) (length l)))
(avg 1 2 3)
]
@;------------------------------------------------------------------------
@section[#:tag "guide:multiple-values"]{Multiple Values}
A Scheme expression normally produces a single result, but some
expressions can produce multiple results. For example,
@scheme[quotient] and @scheme[remainder] each produce a single value,
but @scheme[quotient/remainder] produces the same two values at once:
@interaction[
(quotient 13 3)
(remainder 13 3)
(quotient/remainder 13 3)
]
As shown abpve, the REPL prints each result value on its own line.
Multiple-valued procedures can be implemented in terms of the
@scheme[values] procedure, which takes any number of values and
returns them as the results:
@interaction[
(values 1 2 3)
]
@def+int[
(define (split-name name)
(let ([m (regexp-match #rx"^([^ ]*) (.*)$" name)])
(values (list-ref m 1) (list-ref m 2))))
(split-name "Adam Smith")
]
The @scheme[define-values] form binds multiple identifiers at once to
multiple results produced from a single expression:
@specform[(define-values (id ...) expr)]{}
The number of results produced by the @scheme[_expr] must match the
number of @scheme[_id]s.
@defexamples[
(define-values (given surname) (split-name "Adam Smith"))
given
surname
]
A @scheme[define] form (that is not a procedure shorthand) is
equivalent to a @scheme[define-values] form with a single @scheme[id].
@;------------------------------------------------------------------------
@section[#:tag "guide:intdefs"]{Internal Definitions}
When the grammar for a syntactic form specified @scheme[_body], then
the corresponding position in an instance of the grammar can be either
a definition or an expression.

View File

@ -6,12 +6,78 @@
@title[#:tag "scheme-forms" #:style 'toc]{Expressions and Definitions}
The @secref["to-scheme"] chapter introduced some of Scheme's syntactic
forms: definitions, procedure applications, conditionals, procedures,
local binding, and some iteration forms. This section provides a more
complete coverage of the basic Scheme syntactic forms.
forms: definitions, procedure applications, conditionals, and so
on. This section provides more details on those forms, plus a few
additional basic forms.
@local-table-of-contents[]
@section[#:tag "guide:syntax-notation"]{Notation}
This chapter (and the rest of the documentation) uses a slightly
different notation than the character-based grammars of the
@secref["to-scheme"] chapter. The grammar for a use of a syntactic
form @schemekeywordfont{something} is shown like this:
@specform[(#,(schemekeywordfont "something") [id ...+] an-expr ...)]
The italicized meta-variables in this specification, such as
@scheme[_id] and @scheme[_an-expr], use the syntax of Scheme
identifiers, so @scheme[_an-expr] is one meta-variable. A naming
convention implicitly defines the meaning of many meta-variables:
@itemize{
@item{A meta-variable that ends in @scheme[_id] stands for an
identifier, such as @schemeidfont{x} or
@schemeidfont{my-favorite-martian}.}
@item{A meta-identifier that ends in @scheme[_keyword] stands
for a keyword, such as @scheme[#:tag].}
@item{A meta-identifier that ends with @scheme[_expr] stands for any
sub-form, and it will be parsed as an expression.}
@item{A meta-identifier that ends with @scheme[_body] stands for any
sub-form; it will be parsed as either a local definition or an
expression. A @scheme[_body] can parse as a definition only if
it is not preceded by any expression, and the last
@scheme[_body] must be an expression.}
}
Square brackets in the grammar indicate a parenthesized sequence of
forms, where square brackets are normally used (by convention). That
is square brackets @italic{do not} mean optional parts of the
syntactic form.
A @scheme[...] indicates zero or more repetitions of the preceding
form, and @scheme[...+] indicates one or more repetitions of the
preceding datum. Otherwise, non-italicized identifiers stand form
themselves.
Based on the above grammar, then, here are a few legal uses of
@schemekeywordfont{something}:
@schemeblock[
(#,(schemekeywordfont "something") [x])
(#,(schemekeywordfont "something") [x] (+ 1 2))
(#,(schemekeywordfont "something") [x my-favorite-martian x] (+ 1 2) #f)
]
Some syntactic forms refer to meta-variables that are not implicitly
defined and not previously defined. Such meta-variables are defined
using a BNF-like format for alternatives:
@specform/subs[(#,(schemekeywordfont "something-else") [thing ...+] an-expr ...)
([thing thing-id
thing-keyword])]
The above example says that, within a @schemekeywordfont{something-else}
form, a @scheme[_thing] is either an identifier or a keyword.
@;------------------------------------------------------------------------
@include-section["binding.scrbl"]
@include-section["apply.scrbl"]
@include-section["lambda.scrbl"]

View File

@ -7,6 +7,7 @@
(provide Quick MzScheme HtDP
tool
refdetails
refdetails/gory
refsecref)
(define Quick
@ -21,13 +22,19 @@
(define (tool name . desc)
(apply item (bold name) ", " desc))
(define/kw (refdetails tag #:body s)
(define/kw (refdetails* tag what #:body s)
(apply margin-note
(decode-content (append (list "For more on ")
(decode-content (append (list "For " what " on ")
s
(list ", see "
(refsecref tag)
".")))))
(define/kw (refdetails tag #:body s)
(apply refdetails* tag "more" s))
(define/kw (refdetails/gory tag #:body s)
(apply refdetails* tag "gory details" s))
(define (refsecref s)
(make-element #f (list (secref s) " in " MzScheme))))

View File

@ -24,14 +24,14 @@ precise details to @|MzScheme| and other reference manuals.
@include-section["data.scrbl"]
@include-section["define-struct.scrbl"]
@include-section["forms.scrbl"]
@include-section["define-struct.scrbl"]
@include-section["module-basics.scrbl"]
@; ----------------------------------------------------------------------
@section[#:tag "contracts"]{Contracts}
@section[#:tag "guide:contracts"]{Contracts}
In the reference manual, the documentation for each procedure
describes the acceptable arguments and the result of the procedure
@ -54,7 +54,11 @@ using @idefterm{contracts}.
@; ----------------------------------------------------------------------
@section[#:tag "i/o"]{I/O and Networking}
@section[#:tag "guide:i/o"]{Input and Output}
@; ----------------------------------------------------------------------
@section[#:tag "guide:networking"]{Networking}
@; ----------------------------------------------------------------------
@ -88,6 +92,9 @@ using @idefterm{contracts}.
@; ----------------------------------------------------------------------
@section[#:tag "memory-management"]{Memory Management}
@subsection[#:tag "guide:weakboxes"]{Weak Boxes}
@subsection[#:tag "guide:ephemerons"]{Ephemerons}
@; ----------------------------------------------------------------------
@section[#:tag "performance"]{Performance}

View File

@ -33,7 +33,7 @@ key--value pair. Literal hash tables are immutable.
(hash-table-get ht "apple")
]
@refdetails["mz:parse-hashtable"]{the syntax of hash table literals}
@refdetails/gory["mz:parse-hashtable"]{the syntax of hash table literals}
A hash table can optionally retain its keys @defterm{weakly}, so each
mapping is retained only so long as the key is retained elsewhere.
@ -49,7 +49,7 @@ Beware that even a weak hash table retains its values strongly, as
long as the corresponding key is accessible. This creates a catch-22
dependency when a value refers back to its key, so that the mapping is
retained permanently. To break the cycle, map the key to an
@seclink["ephemerons"]{ephemeron} that pair the value with its key (in
@seclink["guide:ephemerons"]{ephemeron} that pair the value with its key (in
addition to the implicit pairing of the hash table).
@examples[

View File

@ -5,10 +5,10 @@
@title[#:tag "keywords"]{Keywords}
A @defterm{keyword} is similar to a symbol (see @secref["symbols"]),
A @defterm{keyword} is similar to a symbol (see @secref["guide:symbols"]),
but its printed form is prefixed with @litchar{#:}.
@refdetails["mz:parse-keyword"]{the syntax of keywords}
@refdetails/gory["mz:parse-keyword"]{the syntax of keywords}
@examples[
(string->keyword "apple")

View File

@ -3,6 +3,8 @@
@require[(lib "eval.ss" "scribble")]
@require["guide-utils.ss"]
@interaction-eval[(require (rename (lib "etc.ss") lambda opt-lambda))]
@title[#:tag "guide:lambda"]{Procedures: @scheme[lambda] and @scheme[case-lambda]}
A @scheme[lambda] expression creates a procedure. In the simplest
@ -10,13 +12,9 @@ case, a @scheme[lambda] expression has the form
@specform[
(lambda (arg-id ...)
body-expr ...+)
body ...+)
]
The @scheme[...+] in this syntactic sketch means ``one or more
repetitions of the preceeding element.'' Specifically, it means one or
more @scheme[_body-expr]s.
A @scheme[lambda] form with @math{n} @scheme[_arg-id]s accepts
@math{n} arguments:
@ -29,11 +27,14 @@ A @scheme[lambda] form with @math{n} @scheme[_arg-id]s accepts
1)
]
@;------------------------------------------------------------------------
@section{Rest Arguments}
A @scheme[lambda] expression can also have the form
@specform[
(lambda rest-id
body-expr ...+)
body ...+)
]
That is, a @scheme[lambda] expression can have a single
@ -49,108 +50,160 @@ into a list bound to @scheme[_rest-id].
1 2 3)
]
Combining thes two styles, a @scheme[lambda] expression can have the
form
Procedures of this form often use @scheme[apply] to call another
procedure that accepts any number of arguments.
@margin-note{See @secref["guide:apply"] for more information on
@scheme[apply].}
@defexamples[
(define max-mag
(lambda nums
(apply max (map magnitude nums))))
(max 1 -2 0)
(max-mag 1 -2 0)
]
Generalizing the fixed-arity and any-arity style, a @scheme[lambda]
expression can have the form
@specform[
(lambda (arg-id ...+ . rest-id)
body-expr ...+)
body ...+)
]
The result is a procedure that requires at least as many arguments as
@scheme[_arg-id]s, and also accepts any number of additional
arguments.
@examples[
((lambda (a b . x) (cons (/ a b) x))
1 2 3 4)
((lambda (a b . x) (cons (/ a b) x))
1 2)
((lambda (a b . x) (cons (/ a b) x))
1)
@defexamples[
(define max-mag
(lambda (num . nums)
(apply max (map magnitude (cons num nums)))))
(max-mag 1 -2 0)
(max-mag)
]
Support for optional and keyword arguments lead to even more
possibilities:
A @scheme[_rest-id] variable is sometimes called a @defterm{rest
argument}, because it accepts the ``rest'' of the procedure arguments.
@itemize{
@;------------------------------------------------------------------------
@section{Optional Arguments}
@item{Instead of just an @scheme[_arg-id], an form argument can be
@scheme[[_arg-id _default-expr]], which means that the argument
is optional. When the argument is not supplied,
@scheme[_default-expr] produces the default value. The
@scheme[_default-expr] can refer to any preceding
@scheme[_arg-id], and every following @scheme[_arg-id] must
have a default as well.
Instead of just an identifier, an argument (other than a rest
argument) in a @scheme[lambda] form can be specified with an
identifier and a default value:
@examples[
((lambda (x [y 5]) (list x y))
1 2)
((lambda (x [y 5]) (list x y))
1)
((lambda (x [y (+ x 1)]) (list x y))
1)
(lambda ([x 5] y) (list x y))
]}
@specform/subs[
(lambda (arg ...+ . rest-id)
body ...+)
([arg arg-id
[arg-id default-expr]])
]{}
@item{Instead of just an @scheme[_arg-id], an form argument can be
@scheme[(code:line _keyword _arg-id)], which indicates a
by-keyword argument instead of a by-position argument. The
position of the keyword--identifier pair in the argument list
does not matter for matching with arguments in an application,
because it will be matched to an argument value by keyword
insteda of by position.
A argument of the form @scheme[[arg-id default-expr]] is
optional. When the argument is not supplied in an application,
@scheme[_default-expr] produces the default value. The
@scheme[_default-expr] can refer to any preceding @scheme[_arg-id],
and every following @scheme[_arg-id] must have a default as well.
@examples[
((lambda (x #:second y) (list x y))
1 #:second 2)
((lambda (x #:second y) (list x y))
#:second 2 1)
((lambda (#:second y x) (list x y))
1 #:second 2)
((lambda (x #:second y) (list x y))
1 2)
((lambda (x #:second y) (list x y))
#:second 2)
]}
@defexamples[
(define greet
(lambda (given [surname "Smith"])
(string-append "Hello, " given " " surname)))
@item{The previous two possibilities can be combined to specify a
by-keyword argument with a default value.
(greet "John")
(greet "John" "Doe")
]
@examples[
((lambda (x #:second [y 5]) (list x y))
1 #:second 2)
((lambda (x #:second [y 5]) (list x y))
1)
]}
@def+int[
(define greet
(lambda (given [surname (if (equal? given "John")
"Doe"
"Smith")])
(string-append "Hello, " given " " surname)))
}
(greet "John")
(greet "Adam")
]
@section{Keyword Arguments}
A @scheme[lambda] form can declare an argument to be passed by
keyword, instead of position. Keyword arguments can be mixed with
by-position arguments, and default-value expressions can be supplied
for either kind of argument:
@specform/subs[
(lambda (arg ...+ . rest-id)
body ...+)
([arg arg-id
[arg-id default-expr]
(code:line arg-keyword arg-id)
(code:line arg-keyword [arg-id default-expr])])
]{}
As argument specified as @scheme[(code:line _arg-keyword _arg-id)] is
supplied by an application using the same @scheme[_arg-keyword]. The
position of the keyword--identifier pair in the argument list does not
matter for matching with arguments in an application, because it will
be matched to an argument value by keyword instead of by position.
@def+int[
(define greet
(lambda (given #:last surname)
(string-append "Hello, " given " " surname)))
(greet "John" #:last "Smith")
(greet #:last "Doe" "John")
]
A @scheme[(code:line _arg-keyword [_arg-id _default-expr])] argument
specifies a keyword-based argument with a default value.
@defexamples[
(define greet
(lambda (#:hi [hi "Hello"] given #:last [surname "Smith"])
(string-append hi ", " given " " surname)))
(greet "John")
(greet "Karl" #:last "Marx")
(greet "John" #:hi "Howdy")
(greet "Karl" #:last "Marx" #:hi "Guten Tag")
]
@;------------------------------------------------------------------------
@section{Arity-Sensitive Procedures: @scheme[case-lambda]}
The @scheme[case-lambda] form creates a procedure that can have
completely different behaviors depending on the number of arguments
that are supplied. A case-lambda expression has the form
@specform[
@specform/subs[
(case-lambda
[formals body-expr ...+]
[formals body ...+]
...)
([formals (arg-id ...)
rest-id
(arg-id ...+ . rest-id)])
]
where each @scheme[_formals _body-expr ...+] is anlogous to
@scheme[(lambda _formals _body-expr ...+)]. That is, a
@scheme[_formals] can be @scheme[(_arg-id ...)], @scheme[_rest-id], or
@scheme[(_arg-id ... . _rest-id)].
where each @scheme[_formals _body ...+] is anlogous to @scheme[(lambda
_formals _body ...+)]. Applying a procedure produced by
@scheme[case-lambda] is like applying a @scheme[lambda] for the first
case that matches the number of given arguments.
Applying a procedure produced by @scheme[case-lambda] is like applying
a @scheme[lambda] for the first case that matches the number of given
arguments.
@defexamples[
(define greet
(case-lambda
[(name) (string-append "Hello, " name)]
[(given surname) (string-append "Hello, " given " " surname)]))
@examples[
((case-lambda [() 10][(x y) (+ x y)])
1 2)
((case-lambda [() 10][(x y) (+ x y)]))
((case-lambda [() 10][(x y) (+ x y)])
1)
(greet "John")
(greet "John" "Smith")
(greet)
]
A @scheme[case-lambda] procedure cannot directly support optional or

View File

@ -179,7 +179,7 @@ With these pieces, you can write your own versions of the
]
If the derivation of the above definitions is mysterious to you,
consider reading @|HtDP|. But if you are merely suspicious of the use
consider reading @|HtDP|. If you are merely suspicious of the use
of recursive calls instead of a looping construct, then read on.
Both the @scheme[my-length] and @scheme[my-map] procedures run in

View File

@ -53,7 +53,7 @@ or inexact number. The prefixes @litchar{#b}, @litchar{#o}, and
@litchar{#x} specificy binary, octal, and hexadecimal
interprertation of digits.
@refdetails["mz:parse-number"]{the syntax of numbers}
@refdetails/gory["mz:parse-number"]{the syntax of numbers}
@examples[
0.5

View File

@ -43,7 +43,9 @@ with @file{~}---which looks like a reference to the current user's
home directory, instead of a relative path to a file of directory
named @file{~}. Windows path manipulation, furthermore, is far
trickier, because path elements like @file{aux} can have special
meanings (see @secref["windows-path"]).
meanings.
@refdetails/gory["mz:windows-path"]{Windows filesystem paths}
Use procedures like @scheme[split-path] and @scheme[build-path] to
deconstruct and construct paths. When you must manipulate the name of

View File

@ -47,7 +47,7 @@ a sequence as an element for repetition.
@define[and-expr-stx @BNF-seq[@litchar{(} @litchar{and} @kleenestar{@nonterm{expr}} @litchar{)}]]
@define[or-expr-stx @BNF-seq[@litchar{(} @litchar{or} @kleenestar{@nonterm{expr}} @litchar{)}]]
@define[cond-expr-stx @BNF-seq[@litchar{(} @litchar{cond}
@kleenestar{@BNF-group[@litchar{[} @nonterm{expr} @nonterm{expr} @litchar{]}]}
@kleenestar{@BNF-group[@litchar{[} @nonterm{expr} @kleenestar{@nonterm{expr}} @litchar{]}]}
@litchar{)}]]
@define[(make-let-expr-stx kw)
@BNF-seq[@litchar{(} kw @litchar{(}
@ -328,13 +328,13 @@ The shorthand for a sequence of tests is the @scheme[cond] form:
A @scheme[cond] form contains a sequence of clauses between square
brackets. In each clause, the first @nonterm{expr} is a test
expression. If it produces true, then the clause's second
@nonterm{expr} provides the answer for the entire @scheme[cond]
expression, and the rest of the clauses are ignored. If the test
@nonterm{expr} produces @scheme[#f], then the clause's second
@nonterm{expr} is ignored, and evaluation continues with the
next clause. The last clause can use @scheme[else] as a synonym for
a @scheme[#t] test expression.
expression. If it produces true, then the clause's remaining
@nonterm{expr}s are evaluated, and the last one in the clause provides
the answer for the entire @scheme[cond] expression; the rest of the
clauses are ignored. If the test @nonterm{expr} produces @scheme[#f],
then the clause's remaining @nonterm{expr}s are ignored, and
evaluation continues with the next clause. The last clause can use
@scheme[else] as a synonym for a @scheme[#t] test expression.
Using @scheme[cond], the @scheme[reply-more] procedure can be more
clearly written as follows:

View File

@ -59,7 +59,7 @@ special characters or that might otherwise look like numbers.
(string->symbol "6")
]
@refdetails["mz:parse-symbol"]{the syntax of symbols}
@refdetails/gory["mz:parse-symbol"]{the syntax of symbols}
The @scheme[display] form of a symbol is the same as the corresponding
string.

View File

@ -183,7 +183,7 @@ Beware, however, that the REPL's printer recognizes the symbol
]
@;------------------------------------------------------------------------
@section{Lists and Scheme Syntax}
@section[#:tag "guide:lists-and-syntax"]{Lists and Scheme Syntax}
Now that you know the truth about pairs and lists, and now that you've
seen @scheme[quote], you're ready to understand the main way in which

View File

@ -16,7 +16,7 @@ expression. Also, a vector as an expression implicitly quotes the
forms for its content, which means that identifiers and parenthesized
forms in a vector constant represent symbols and lists.
@refdetails["mz:parse-vector"]{the syntax of vectors}
@refdetails/gory["mz:parse-vector"]{the syntax of vectors}
@examples[
(eval:alts #, @schemevalfont{#("a" "b" "c")} #("a" "b" "c"))

View File

@ -13,7 +13,7 @@ A @pidefterm{byte string} is a fixed-length arary of bytes. A
@defterm{mutable} or @defterm{immutable}. When an immutable byte
string is provided to a procedure like @scheme[bytes-set!], the
@exnraise[exn:fail:contract]. Byte-string constants generated by the
default reader (see @secref["parse-string"]) are immutable.
default reader (see @secref["mz:parse-string"]) are immutable.
Two byte strings are @scheme[eq?] when mutating one would mutate the
other. Two byte strings are @scheme[eqv?] and @scheme[equal?] when

View File

@ -7,3 +7,14 @@
A @pidefterm{character} corresponds to a Unicode scalar value (i.e., a
Unicode code point that is not a surrogate).
@; ----------------------------------------
@section{Classifications}
@defproc[(char-alphabetic? [char character?]) boolean?]{
Returns @scheme[#t] if @scheme[char] is alphabetic...
}
@defproc[(char-whitespace? [char character?]) boolean?]{
Returns @scheme[#t] if @scheme[char] is whitespace...
}

View File

@ -34,14 +34,14 @@ is @scheme[#t] or @scheme[#f], @scheme[#f] otherwise.}
@include-section["chars.scrbl"]
@; ------------------------------------------------------------
@section[#:tag "symbols"]{Symbols}
@section[#:tag "mz:symbols"]{Symbols}
@guideintro["guide:symbols"]{symbols}
A symbol is like an immutable string, but symbols are normally
@index["interned symbols"]{@defterm{interned}}, so that two symbols
with the same character content are normally @scheme[eq?]. All symbols
produced by the default reader (see @secref["parse-symbol"]) are
produced by the default reader (see @secref["mz:parse-symbol"]) are
interned.
@index['("symbols" "generating")]{@index['("symbols" "unique")]{The}} two
@ -54,8 +54,8 @@ Regular (interned) symbols are only weakly held by the internal symbol
table. This weakness can never affect the result of an @scheme[eq?],
@scheme[eqv?], or @scheme[equal?] test, but a symbol may disappear
when placed into a weak box (see @secref["weakbox"]) used as the key
in a weak hash table (see @secref["hashtable"]), or used as an
ephemeron key (see @secref["ephemeron"]).
in a weak hash table (see @secref["mz:hashtables"]), or used as an
ephemeron key (see @secref["mz:ephemerons"]).
@defproc[(symbol? [v any/c]) boolean?]{Returns @scheme[#t] if @scheme[v] is
a symbol, @scheme[#f] otherwise.}
@ -190,13 +190,19 @@ If the @scheme[lst]s are empty, then @scheme[#f] is returned.}
ignored.}
@; ------------------------------------------------------------
@section[#:tag "mz:vectors"]{Vectors}
@; ------------------------------------------------------------
@section[#:tag "mz:boxes"]{Boxes}
@; ----------------------------------------------------------------------
@section[#:tag "hashtables"]{Hash Tables}
@section[#:tag "mz:hashtables"]{Hash Tables}
@; ----------------------------------------------------------------------
@include-section["sequences.scrbl"]
@section[#:tag "procedures"]{Procedures}
@section[#:tag "mz:procedures"]{Procedures}
@; ----------------------------------------------------------------------
@section[#:tag "void"]{Void and Undefined}

View File

@ -1,211 +1,8 @@
#reader(lib "docreader.ss" "scribble")
@require["mz.ss"]
@interaction-eval[(require (lib "for.ss"))]
@title[#:tag "mz:derived-syntax" #:style 'toc]{Derived Syntactic Forms}
@title[#:tag "mz:derived-syntax"]{Derived Syntactic Forms}
@section[#:tag "mz:for"]{Iterations and Comprehensions: @scheme[for], @scheme[for/list], ...}
@guideintro["guide:for"]{iterations and comprehensions}
@defform/subs[(for (for-clause ...) . body)
([for-clause [id seq-expr]
[(id ...) seq-expr]
(code:line #:when guard-expr)])]{
Iteratively evaluates @scheme[body]. The @scheme[for-clause]s
introduce bindings whose scope inculdes @scheme[body] and that
determine the number of times that @scheme[body] is evaluated.
In the simple case, each @scheme[for-clause] has one of its first two
forms, where @scheme[[id seq-expr]] is a shorthand for @scheme[[(id
...) seq-expr]]. In this simple case, the @scheme[seq-expr]s are
evaluated left-to-right, and each must produce a sequence value (see
@secref["mz:sequences"]).
The @scheme[for] form iterates by drawing an element from each
sequence; if any sequence is empty, then the iteration stops, and
@|void-const| is the result of the @scheme[for] expression. Otherwise
a location is created for each @scheme[id] to hold the values of each
element; the sequence produced by a @scheme[seq-expr] must return as
many values for each iteration as corresponding @scheme[id]s.
The @scheme[id]s are then bound in the @scheme[body], which is
evaluated, and whose results are ignored. Iteration continues with the
next element in each sequence and with fresh locations for each
@scheme[id].
A @scheme[for] form with zero @scheme[for-clause]s is equivalent to a
single @scheme[for-clause] that binds an unreferenced @scheme[id] to
a sequence containing a single element. All of the @scheme[id]s must
be distinct according to @scheme[bound-identifier=?].
If any @scheme[for-clause] has the form @scheme[#:when guard-expr],
then only the preceding clauses (containing no @scheme[#:when])
determine iteration as above, and the @scheme[body] is effectively
wrapped as
@schemeblock[
(when guard-expr
(for (for-clause ...) . body))
]
using the remaining @scheme[for-clauses].
@examples[
(for ([i '(1 2 3)]
[j "abc"]
#:when (odd? i)
[k #2(#t #f)])
(display (list i j k)))
(for ([(i j) #hash(("a" . 1) ("b" . 20))])
(display (list i j)))
(for ()
(display "here"))
(for ([i '()])
(error "doesn't get here"))
]}
@defform[(for/list (for-clause ...) . body)]{ Iterates like
@scheme[for], but that the last expression of @scheme[body] must
produce a single value, and the result of the @scheme[for/list]
expression is a list of the results in order.
@examples[
(for/list ([i '(1 2 3)]
[j "abc"]
#:when (odd? i)
[k #2(#t #f)])
(list i j k))
(for/list () 'any)
(for/list ([i '()])
(error "doesn't get here"))
]}
@defform[(for/and (for-clause ...) . body)]{ Iterates like
@scheme[for], but when last expression of @scheme[body] produces
@scheme[#f], then iteration terminates, and the result of the
@scheme[for/and] expression is @scheme[#f]. If the @scheme[body]
is never evaluated, then the result of the @scheme[for/and]
expression is @scheme[#t]. Otherwise, the result is the (single)
result from the last evaluation of @scheme[body].
@examples[
(for/and ([i '(1 2 3 "x")])
(i . < . 3))
(for/and ([i '(1 2 3 4)])
i)
(for/and ([i '()])
(error "doesn't get here"))
]}
@defform[(for/or (for-clause ...) . body)]{ Iterates like
@scheme[for], but when last expression of @scheme[body] produces
a value other than @scheme[#f], then iteration terminates, and
the result of the @scheme[for/or] expression is the same
(single) value. If the @scheme[body] is never evaluated, then the
result of the @scheme[for/or] expression is
@scheme[#f]. Otherwise, the result is @scheme[#f].
@examples[
(for/or ([i '(1 2 3 "x")])
(i . < . 3))
(for/or ([i '(1 2 3 4)])
i)
(for/or ([i '()])
(error "doesn't get here"))
]}
@defform[(for/first (for-clause ...) . body)]{ Iterates like
@scheme[for], but after @scheme[body] is evaluated the first
time, then the iteration terminates, and the @scheme[for/first]
result is the (single) result of @scheme[body]. If the
@scheme[body] is never evaluated, then the result of the
@scheme[for/first] expression is @scheme[#f].
@examples[
(for/first ([i '(1 2 3 "x")]
#:when (even? i))
(number->string i))
(for/first ([i '()])
(error "doesn't get here"))
]}
@defform[(for/last (for-clause ...) . body)]{ Iterates like
@scheme[for], but the @scheme[for/last] result is the (single)
result of of the last evaluation of @scheme[body]. If the
@scheme[body] is never evaluated, then the result of the
@scheme[for/last] expression is @scheme[#f].
@examples[
(for/last ([i '(1 2 3 4 5)]
#:when (even? i))
(number->string i))
(for/last ([i '()])
(error "doesn't get here"))
]}
@defform[(for/fold ([accum-id init-expr] ...) (for-clause ...). body)]{
Iterates like @scheme[for]. Before iteration starts, the
@scheme[init-expr]s are evaluated to produce initial accumulator
values. At the start of each out iteration, a location is generated
for each @scheme[accum-id], and the correspinding current accumulator
value is placed into the location. The last expression in
@scheme[body] must produce as many values as @scheme[accum-id]s, and
those values become the current accumulator values. When iteration
terminates, the results of the @scheme[fold/for] expression are the
accumulator values.
@examples[
(for/fold ([sum 0]
[rev-roots null])
([i '(1 2 3 4)])
(values (+ sum i) (cons (sqrt i) rev-roots)))
]}
@defform[(for* (for-clause ...) . body)]{
Like @scheme[for], but with an implicit @scheme[#:when #t] between
each pair of @scheme[for-clauses], so that all sequence iterations are
nested.
@examples[
(for* ([i '(1 2)]
[j "ab"])
(display (list i j)))
]}
@defform[(for*/list (for-clause ...) . body)]{
Like @scheme[for/list], but with the implicit nesting of @scheme[for*].
@examples[
(for*/list ([i '(1 2)]
[j "ab"])
(list i j))
]}
@defform[(for*/and (for-clause ...) . body)]{
Like @scheme[for/and], but with the implicit nesting of @scheme[for*].}
@defform[(for*/or (for-clause ...) . body)]{
Like @scheme[for/or], but with the implicit nesting of @scheme[for*].}
@defform[(for*/first (for-clause ...) . body)]{
Like @scheme[for/first], but with the implicit nesting of @scheme[for*].}
@defform[(for*/last (for-clause ...) . body)]{
Like @scheme[for/last], but with the implicit nesting of @scheme[for*].}
@defform[(for*/fold ([accum-id init-expr] ...) (for-clause ...) . body)]{
Like @scheme[for/fold], but with the implicit nesting of @scheme[for*].}
@defform[(for/fold/derived orig-datum
([accum-id init-expr] ...) (for-clause ...) . body)]{
Like @scheme[fold/fold], but the extra @scheme[orig-datum] is used as the source for all syntax errors.
}
@defform[(for*/fold/derived orig-datum
([accum-id init-expr] ...) (for-clause ...) . body)]{
Like @scheme[fold*/fold], but the extra @scheme[orig-datum] is used as the source for all syntax errors.
}
@local-table-of-contents[]
@include-section["for.scrbl"]

View File

@ -0,0 +1,281 @@
#reader(lib "docreader.ss" "scribble")
@require["mz.ss"]
@interaction-eval[(require (lib "for.ss"))]
@title[#:tag "mz:for"]{Iterations and Comprehensions: @scheme[for], @scheme[for/list], ...}
@guideintro["guide:for"]{iterations and comprehensions}
The PLT Scheme iteration forms are based on SRFI-42
@cite[#:key "srfi-42"
#:title "SRFI-42: Eager Comprehensions"
#:author "Sebastian Egner"
#:location "http://srfi.schemers.org/srfi-42/"
#:date "2003"].
@section{Iteration and Comprehension Forms}
@defform/subs[(for (for-clause ...) . body)
([for-clause [id seq-expr]
[(id ...) seq-expr]
(code:line #:when guard-expr)])]{
Iteratively evaluates @scheme[body]. The @scheme[for-clause]s
introduce bindings whose scope inculdes @scheme[body] and that
determine the number of times that @scheme[body] is evaluated.
In the simple case, each @scheme[for-clause] has one of its first two
forms, where @scheme[[id seq-expr]] is a shorthand for @scheme[[(id
...) seq-expr]]. In this simple case, the @scheme[seq-expr]s are
evaluated left-to-right, and each must produce a sequence value (see
@secref["mz:sequences"]).
The @scheme[for] form iterates by drawing an element from each
sequence; if any sequence is empty, then the iteration stops, and
@|void-const| is the result of the @scheme[for] expression. Otherwise
a location is created for each @scheme[id] to hold the values of each
element; the sequence produced by a @scheme[seq-expr] must return as
many values for each iteration as corresponding @scheme[id]s.
The @scheme[id]s are then bound in the @scheme[body], which is
evaluated, and whose results are ignored. Iteration continues with the
next element in each sequence and with fresh locations for each
@scheme[id].
A @scheme[for] form with zero @scheme[for-clause]s is equivalent to a
single @scheme[for-clause] that binds an unreferenced @scheme[id] to
a sequence containing a single element. All of the @scheme[id]s must
be distinct according to @scheme[bound-identifier=?].
If any @scheme[for-clause] has the form @scheme[#:when guard-expr],
then only the preceding clauses (containing no @scheme[#:when])
determine iteration as above, and the @scheme[body] is effectively
wrapped as
@schemeblock[
(when guard-expr
(for (for-clause ...) . body))
]
using the remaining @scheme[for-clauses].
@examples[
(for ([i '(1 2 3)]
[j "abc"]
#:when (odd? i)
[k #2(#t #f)])
(display (list i j k)))
(for ([(i j) #hash(("a" . 1) ("b" . 20))])
(display (list i j)))
(for ()
(display "here"))
(for ([i '()])
(error "doesn't get here"))
]}
@defform[(for/list (for-clause ...) . body)]{ Iterates like
@scheme[for], but that the last expression of @scheme[body] must
produce a single value, and the result of the @scheme[for/list]
expression is a list of the results in order.
@examples[
(for/list ([i '(1 2 3)]
[j "abc"]
#:when (odd? i)
[k #2(#t #f)])
(list i j k))
(for/list () 'any)
(for/list ([i '()])
(error "doesn't get here"))
]}
@defform[(for/and (for-clause ...) . body)]{ Iterates like
@scheme[for], but when last expression of @scheme[body] produces
@scheme[#f], then iteration terminates, and the result of the
@scheme[for/and] expression is @scheme[#f]. If the @scheme[body]
is never evaluated, then the result of the @scheme[for/and]
expression is @scheme[#t]. Otherwise, the result is the (single)
result from the last evaluation of @scheme[body].
@examples[
(for/and ([i '(1 2 3 "x")])
(i . < . 3))
(for/and ([i '(1 2 3 4)])
i)
(for/and ([i '()])
(error "doesn't get here"))
]}
@defform[(for/or (for-clause ...) . body)]{ Iterates like
@scheme[for], but when last expression of @scheme[body] produces
a value other than @scheme[#f], then iteration terminates, and
the result of the @scheme[for/or] expression is the same
(single) value. If the @scheme[body] is never evaluated, then the
result of the @scheme[for/or] expression is
@scheme[#f]. Otherwise, the result is @scheme[#f].
@examples[
(for/or ([i '(1 2 3 "x")])
(i . < . 3))
(for/or ([i '(1 2 3 4)])
i)
(for/or ([i '()])
(error "doesn't get here"))
]}
@defform[(for/first (for-clause ...) . body)]{ Iterates like
@scheme[for], but after @scheme[body] is evaluated the first
time, then the iteration terminates, and the @scheme[for/first]
result is the (single) result of @scheme[body]. If the
@scheme[body] is never evaluated, then the result of the
@scheme[for/first] expression is @scheme[#f].
@examples[
(for/first ([i '(1 2 3 "x")]
#:when (even? i))
(number->string i))
(for/first ([i '()])
(error "doesn't get here"))
]}
@defform[(for/last (for-clause ...) . body)]{ Iterates like
@scheme[for], but the @scheme[for/last] result is the (single)
result of of the last evaluation of @scheme[body]. If the
@scheme[body] is never evaluated, then the result of the
@scheme[for/last] expression is @scheme[#f].
@examples[
(for/last ([i '(1 2 3 4 5)]
#:when (even? i))
(number->string i))
(for/last ([i '()])
(error "doesn't get here"))
]}
@defform[(for/fold ([accum-id init-expr] ...) (for-clause ...). body)]{
Iterates like @scheme[for]. Before iteration starts, the
@scheme[init-expr]s are evaluated to produce initial accumulator
values. At the start of each out iteration, a location is generated
for each @scheme[accum-id], and the correspinding current accumulator
value is placed into the location. The last expression in
@scheme[body] must produce as many values as @scheme[accum-id]s, and
those values become the current accumulator values. When iteration
terminates, the results of the @scheme[fold/for] expression are the
accumulator values.
@examples[
(for/fold ([sum 0]
[rev-roots null])
([i '(1 2 3 4)])
(values (+ sum i) (cons (sqrt i) rev-roots)))
]}
@defform[(for* (for-clause ...) . body)]{
Like @scheme[for], but with an implicit @scheme[#:when #t] between
each pair of @scheme[for-clauses], so that all sequence iterations are
nested.
@examples[
(for* ([i '(1 2)]
[j "ab"])
(display (list i j)))
]}
@defform[(for*/list (for-clause ...) . body)]{
Like @scheme[for/list], but with the implicit nesting of @scheme[for*].
@examples[
(for*/list ([i '(1 2)]
[j "ab"])
(list i j))
]}
@defform[(for*/and (for-clause ...) . body)]{
Like @scheme[for/and], but with the implicit nesting of @scheme[for*].}
@defform[(for*/or (for-clause ...) . body)]{
Like @scheme[for/or], but with the implicit nesting of @scheme[for*].}
@defform[(for*/first (for-clause ...) . body)]{
Like @scheme[for/first], but with the implicit nesting of @scheme[for*].}
@defform[(for*/last (for-clause ...) . body)]{
Like @scheme[for/last], but with the implicit nesting of @scheme[for*].}
@defform[(for*/fold ([accum-id init-expr] ...) (for-clause ...) . body)]{
Like @scheme[for/fold], but with the implicit nesting of @scheme[for*].}
@;------------------------------------------------------------------------
@section{Deriving New Iteration Forms}
@defform[(for/fold/derived orig-datum
([accum-id init-expr] ...) (for-clause ...) . body)]{
Like @scheme[fold/fold], but the extra @scheme[orig-datum] is used as the source for all syntax errors.
}
@defform[(for*/fold/derived orig-datum
([accum-id init-expr] ...) (for-clause ...) . body)]{
Like @scheme[fold*/fold], but the extra @scheme[orig-datum] is used as the source for all syntax errors.
}
@defform[(define-sequence-syntax id
expr-transform-expr
clause-transform-expr)]{
Defines @scheme[id] as syntax. An @scheme[(id . _rest)] form is
treated specially when used to generate a sequence in a
@scheme[_clause] of @scheme[for] (or one of its variants). In that
case, the procedure result of @scheme[clause-transform-expr] is called
to transform the clause.
When @scheme[id] is used in any other expression position, the result
of @scheme[expr-transform-expr] is used; if it is an identifier
@scheme[_other-id], then any use of @scheme[id] is converted to a use
of @scheme[_other-id]; otherwise,@scheme[expr-transform-expr] must
produce a procedure that is used as a macro transformer.
When the @scheme[clause-transform-expr] transformer is used, it is
given a @scheme[_clause] as an argument, where the clause's form is
normalized so that the left-hand side is a parenthesized sequence of
identifiers. The right-hand side is of the form @scheme[(id . _rest)].
The result can be either @scheme[#f], to indicate that the forms
should not be treated specially (perhaps because the number of bound
identifiers is inconsistent with the @scheme[(id . _rest)] form), or a
new @scheme[_clause] to to replace the given one. The new clause might
use @scheme[:do-in].}
@defform[(:do-in ([(outer-id ...) outer-expr] ...)
outer-check
([loop-id loop-expr] ...)
pos-guard
([(inner-id ...) inner-expr] ...)
pre-guard
post-guard
(loop-arg ...))]{
A form that can only be used as a @scheme[_seq-expr] in a
@scheme[_clause] of @scheme[for] (or one of its variants).
Within a @scheme[for], the pieces of the @scheme[:do-in] form are
spliced into the iteration essentially as follows:
@schemeblock[
(let-values ([(outer-id ...) outer-expr] ...)
outer-check
(let loop ([loop-id loop-expr] ...)
(if pos-guard
(let-values ([(inner-id ...) inner-expr] ...)
(if pre-guard
(let _body-bindings
(loop loop-arg ...))
_done-expr))
_done-expr)))
]
where @scheme[_body-bindings] and @scheme[_done-expr] are from the
context of the @scheme[:do-in] use. The actual @scheme[loop] binding
and call has additional loop arguments to support iterations in
parallel with the @scheme[:do-in] form, and the other pieces are
similarly accompanied by pieces form parallel iterations.}

View File

@ -101,6 +101,10 @@ possible contexts are as follows:
}
@section[#:tag "mz:intdef-body"]{Internal Definitions}
@section{Fully Expanded Programs}
A fully expanded program---that is, a parsed program---is represented
in the same way as an unparsed program: as a syntax-wrapped
combination of symbols, pairs, and other values. However, a fully

View File

@ -188,13 +188,13 @@ noted above). Two numbers are @scheme[equal?] when they are
@examples[(/ 3 4) (/ 81 3 3) (/ 10.0) (/ 1+2i 3+4i)]
@defproc[(quotient [n integer?] [m integer?]) number?]{ Returns
@defproc[(quotient [n integer?] [m integer?]) integer?]{ Returns
@scheme[(truncate (/ n m))].}
@examples[(quotient 10 3) (quotient -10.0 3) (quotient +inf.0 3)]
@defproc[(remainder [n integer?] [m integer?]) number?]{ Returns
@defproc[(remainder [n integer?] [m integer?]) integer?]{ Returns
@scheme[q] with the same sign as @scheme[n] such that
@itemize{
@ -208,6 +208,15 @@ noted above). Two numbers are @scheme[equal?] when they are
@examples[(remainder 10 3) (remainder -10.0 3) (remainder 10.0 -3) (remainder -10 -3) (remainder +inf.0 3)]}
@defproc[(quotient/remainder [n integer?] [m integer?]) (values number? number?)]{ Returns
@scheme[(values (quotient n m) (remainder n m))], but the combination is computed
more efficiently than separate calls to @scheme[quotient] and @scheme[remainder].
@examples[
(quotient/remainder 10 3)
]}
@defproc[(modulo [n integer?] [m integer?]) number?]{ Returns
@scheme[q] with the same sign as @scheme[m] where
@ -534,7 +543,7 @@ noted above). Two numbers are @scheme[equal?] when they are
@defproc[(string->number [s string?] [radix (exact-integer-in/c 2 16)
10]) (or/c number? false/c)]{ Reads and returns a number datum from
@scheme[s] (see @secref["parse-number"]), returning @scheme[#f] if
@scheme[s] (see @secref["mz:parse-number"]), returning @scheme[#f] if
@scheme[s] does not parse exactly as a number datum (with no
whitespace). The optional @scheme[radix] argument specifies the default
base for the number, which can be overriden by @litchar{#b},

View File

@ -18,7 +18,7 @@
@title[#:tag "mz:reader"]{Reading}
Scheme's reader is a recursive-descent parser that can be configured
through a @seclink["readtable"]{readtable} and various other
through a @seclink["mz:readtables"]{readtable} and various other
@seclink["parameters"]{parameters}. This section describes the reader's
parsing when using the default readtable.
@ -37,10 +37,10 @@ reader's behavior in @scheme[read] mode, and @scheme[read-syntax] mode
does the same modulo wrapping the final result.
Reading is defined in terms of Unicode characters; see
@secref["unicode"] for information on how a byte stream is converted
@secref["mz:char-input"] for information on how a byte stream is converted
to a character stream.
@section{Delimiters and Dispatch}
@section[#:tag "mz:default-readtable-dispatch"]{Delimiters and Dispatch}
Along with @schemelink[char-whitespace?]{whitespace}, the following
characters are @defterm{delimiters}:
@ -286,7 +286,7 @@ input syntax for the boolean constant false.
When the reader encounters a @as-index{@litchar{(}},
@as-index{@litchar["["]}, or @as-index{@litchar["{"]}, it starts
parsing a pair or list; see @secref["pairs"] for information on pairs
parsing a pair or list; see @secref["mz:pairs"] for information on pairs
and lists.
To parse the pair or list, the reader recursively reads data
@ -720,3 +720,11 @@ information on special-comment results and recursive reads.
If the @scheme[read-accept-reader] parameter is set to @scheme[#f],
then if the reader encounters @litchar{#reader}, the
@exnraise[exn:fail:read].
@section[#:tag "mz:readtables"]{Readtables}
The dispatch table in @secref["mz:default-readtable-dispatch"]
corresponds to the default @idefterm{readtable}.
@section[#:tag "mz:parse-honu"]{Honu Parsing}

View File

@ -18,4 +18,20 @@ language.
@include-section["derived.scrbl"]
@include-section["data.scrbl"]
@;------------------------------------------------------------------------
@section["Input and Output"]
@subsection[#:tag "mz:char-input"]{Form Bytes to Characters}
@;------------------------------------------------------------------------
@section{Platform-Specific Path Conventions}
@subsection[#:tag "mz:unix-path"]{Unix and Mac OS X Paths}
@subsection[#:tag "mz:windows-path"]{Windows Paths}
@;------------------------------------------------------------------------
@index-section["mzscheme-index"]

View File

@ -3,16 +3,16 @@
@title[#:tag "mz:strings"]{Strings}
@guideintro["guide:string"]{strings}
@guideintro["guide:strings"]{strings}
A @pidefterm{string} is a fixed-length arary of
@seclink["characters"]{characters}.
@seclink["mz:characters"]{characters}.
@index['("strings" "immutable")]{A} string can be @defterm{mutable} or
@defterm{immutable}. When an immutable string is provided to a
procedure like @scheme[string-set!], the
@exnraise[exn:fail:contract]. String constants generated by the
default reader (see @secref["parse-string"]) are
default reader (see @secref["mz:parse-string"]) are
immutable.
Two strings are @scheme[eq?] when mutating one would mutate the other.

View File

@ -27,9 +27,6 @@ Within such specifications,
@item{@scheme[...+] indicates one or
more repetitions of the preceding datum.}
@item{@scheme[?] means zero instances or one instance
of the preceding datum.}
@item{italic meta-identifier play the role of non-terminals; in
particular,
@ -48,7 +45,7 @@ Within such specifications,
for a non-empty syntax-wrapped list of sub-forms; the
list is expanded as internal-definition sequence
followed by at least one expression (see
@secref["intdef-body"] for details).}
@secref["mz:intdef-body"] for details).}
}} }
@ -230,7 +227,7 @@ a sequence of @scheme[_formal-arg]s optionally ending with a
list that is associated to @scheme[rest-id].}
The @scheme[formals*] identifiers are bound in the @scheme[body]. (See
@secref["intdef-body"] for information on @scheme[body] forms.) When
@secref["mz:intdef-body"] for information on @scheme[body] forms.) When
the procedure is applied, a new location is created for each
identifier, and the location is filled with the associated argument
value.
@ -299,7 +296,7 @@ support keyword and optional arguments.
The first form evaluates the @scheme[val-expr]s left-to-right, creates
a new location for each @scheme[id], and places the values into the
locations. It then evaluates the @scheme[body], in which the
@scheme[id]s are bound. (See @secref["intdef-body"] for information
@scheme[id]s are bound. (See @secref["mz:intdef-body"] for information
on @scheme[body] forms.) The last expression in @scheme[body] is in
tail position with respect to the @scheme[let] form. The @scheme[id]s
must be distinct according to @scheme[bound-identifier=?].

View File

@ -1,3 +1,9 @@
Version 370.3
Fixed (get-face-list 'mono) for Mac OS X and X11
Changed begin-container-sequence to delay making windows visible
Version 370.2
Added 'no-focus style for canvas%

View File

@ -1,4 +1,4 @@
Version 370.2
Version 370.3
Added hash-table-iterate-{first,next,key,value}
Version 370.2