new documentation source moved to the trunk collects

svn: r6249
This commit is contained in:
Matthew Flatt 2007-05-24 02:20:28 +00:00
parent 1df4472556
commit 858c8024ef
69 changed files with 7030 additions and 0 deletions

View File

@ -0,0 +1,16 @@
(module core mzscheme
(require "to-html.ss"
(prefix ref: "reference/reference.scrbl")
(prefix guide: "guide/guide.scrbl"))
(provide build)
(define (build)
(to-html #t #t
(list ref:doc
guide:doc)
(list "reference"
"guide"))))

View File

@ -0,0 +1,13 @@
(module doc-installer mzscheme
(require (lib "dirs.ss" "setup")
(prefix core: "core.ss")
(prefix quick: "quick.ss"))
(provide post-installer)
(define post-installer
(lambda (path)
(let ([doc (find-doc-dir)])
(when doc
(core:build)
(quick:build))))))

View File

@ -0,0 +1,20 @@
(module guide-utils mzscheme
(require (lib "manual.ss" "scribble"))
(provide Quick MzScheme HtDP
tool)
(define Quick
(link "../quick/index.html" "An Introduction to PLT Scheme with Pictures"))
(define MzScheme
(link "../reference/index.html" "PLT Scheme Reference Manual"))
(define HtDP
(italic (link "http://www.htdp.org" "How to Design Programs")))
(define (tool name . desc)
(apply item (bold name) ", " desc)))

View File

@ -0,0 +1,166 @@
#reader(lib "docreader.ss" "scribble")
@require[(lib "manual.ss" "scribble")]
@require[(lib "eval.ss" "scribble")]
@require["guide-utils.ss"]
@title{A Guide to PLT Scheme}
This guide is intended for programmers who are new to Scheme, new to
PLT Scheme, or new to some part of PLT Scheme.
If you are new to programming, consider instead reading @|HtDP|.
If you want a quicker, prettier, higher-level overview of PLT Scheme,
start with @|Quick|.
For everyone else, this guide assumes some programming experience.
After a somewhat gentle introduction to Scheme (chapters 1 through 4),
we dive into the details of putting Scheme to work. This guide covers
much of the PLT Scheme toolbox, but it leaves the nitty-gritty details
to @|MzScheme| and other reference manuals.
@table-of-contents[]
@include-section["welcome.scrbl"]
@include-section["syntax.scrbl"]
@include-section["lists.scrbl"]
@include-section["truth.scrbl"]
@; ----------------------------------------------------------------------
@section[#:tag "datatypes"]{Built-In and Programmer-Defined Datatypes}
We have seen some of Scheme's built-in datatypes, including numbers,
strings, lists, and procedures. This section provides a more complete
coverage of the built-in datatypes, and also introduces the
@scheme[define-struct] form for creating your own datatypes. We defer
a discussion of the class-based object system to @secref["classes"].
...
@; ----------------------------------------------------------------------
@section[#:tag "scheme-read"]{Reading and Printing}
As we mentioned @seclink["syntax-overview"]{before}, the syntax
of a Scheme program is specified in an unusual way. Specifically, it
is defined by two phases:
@itemize{
@item{a @defterm{read} phase, which parses a stream of characters
into a tree-structured @defterm{S-expression}; and}
@item{an @defterm{expand} phase, which parses the S-expression into a
program.}
}
The second phase is particularly easy to extend, so that Scheme has no
grammar in the traditional sense. At the same time, the first phase is
useful on it's own, and directly available through the @scheme[read]
function. Furthermore, reading of data is naturally matched with
conventions for @defterm{printing} data.
@; ----------------------------------------------------------------------
@section[#:tag "scheme-forms"]{Programs and Expressions}
@subsection{Module Basics}
@subsection{Definition and Expression Forms}
@; ----------------------------------------------------------------------
@section[#:tag "contracts"]{Contracts}
In the reference manual, the documentation for each procedure
describes the acceptable arguments and the result of the procedure
using @idefterm{contracts}.
@; ----------------------------------------------------------------------
@section[#:tag "classes"]{Classes and Objects}
@; ----------------------------------------------------------------------
@section[#:tag "control"]{Exceptions and Control}
@; ----------------------------------------------------------------------
@section[#:tag "threads"]{Threads}
@; ----------------------------------------------------------------------
@section[#:tag "i/o"]{I/O and Networking}
@; ----------------------------------------------------------------------
@section[#:tag "regexp"]{Regular-Expression Matching (Regexps)}
@; ----------------------------------------------------------------------
@section[#:tag "match"]{Pattern Matching}
@; ----------------------------------------------------------------------
@section[#:tag "units"]{Higher-Order Modules (Units)}
@; ----------------------------------------------------------------------
@section[#:tag "macros"]{Syntactic Extension (Modules and Macros)}
@; ----------------------------------------------------------------------
@section[#:tag "reflection"]{Reflection and Dynamic Evaluation}
@; ----------------------------------------------------------------------
@section[#:tag "macros"]{Reader Extension}
@; ----------------------------------------------------------------------
@section[#:tag "security"]{Security}
@; ----------------------------------------------------------------------
@section[#:tag "memory-management"]{Memory Management}
@; ----------------------------------------------------------------------
@section[#:tag "performance"]{Performance}
@; ----------------------------------------------------------------------
@section[#:tag "ffi"]{Foreign-Function Interface (FFI)}
@; ----------------------------------------------------------------------
@section[#:tag "scripts"]{Scripts}
@; ----------------------------------------------------------------------
@section[#:tag "gui"]{Graphical User Interfaces (GUIs)}
@; ----------------------------------------------------------------------
@section[#:tag "tools"]{More Tools}
In the @seclink["intro"]{introduction}, we mentioned that PLT Scheme
includes more tools bsides DrScheme and MzScheme:
@itemize{
@tool["MrEd"]{extends MzScheme with graphical user interface (GUI)
and drawing primitives}
@tool["Setup PLT"]{a command-line tool for installation tasks}
@tool["planet"]{a command-line tool for managing packages that are
normally downloaded automatically, on demand}
@tool["mzc"]{a command-line tool for miscellaneous tasks, such as
compiling Scheme source, compiling C-implemented extensions to the
run-time system, generating executables, and building distribution
packages}
}
@; ----------------------------------------------------------------------
@index-section["guide-index"]

View File

@ -0,0 +1,475 @@
#reader(lib "docreader.ss" "scribble")
@require[(lib "manual.ss" "scribble")]
@require[(lib "eval.ss" "scribble")]
@require[(lib "bnf.ss" "scribble")]
@require["guide-utils.ss"]
@interaction-eval[(require (lib "list.ss"))]
@interaction-eval[(require (lib "for.ss"))]
@define[step @elem{=}]
@title{Lists, Iteration, and Recursion}
Scheme is a dialect of the language Lisp, whose name originally stood
for ``LISt Processor.'' The built-in list datatype remains a prominent
feature of the language.
The @scheme[list] procedure takes any number of values and returns
a list containing the values:
@interaction[(list "red" "green" "blue")
(list 1 2 3 4 5)]
As you can see, a list result prints in the REPL as a pair of
parentheses wrapped around the printed form of the list
elements. There's an opportunity for confusion here, because
parentheses are used for both expressions, such as @scheme[(list "red"
"green" "blue")], and printed results, such as @schemeresult[("red"
"green" "blue")]. Rememeber that, in the documentation and in
DrScheme, parentheses for results are printed in blue, whereas
parentheses for expressions are brown.
Many predefined procedures operate on lists. Here are a few examples:
@interaction[
(code:line (length (list "a" "b" "c")) (code:comment #, @t{count the elements}))
(code:line (list-ref (list "a" "b" "c") 0) (code:comment #, @t{extract an element by position}))
(list-ref (list "a" "b" "c") 1)
(code:line (append (list "a" "b") (list "c")) (code:comment #, @t{combine lists}))
(code:line (reverse (list "a" "b" "c")) (code:comment #, @t{reverse order}))
(code:line (member "d" (list "a" "b" "c")) (code:comment #, @t{check for an element}))
]
@;------------------------------------------------------------------------
@section{Predefined List Loops}
In addition to simple operations like @scheme[append], Scheme includes
procedures that iterate over the elements of a list. These iteration
procedures play the same role as, say, @tt{for} in Java. The body of
an iteration is packaged into a procedure to be applied to each
element, so the @scheme[lambda] form becomes particularly handy in
combination with iteration procedures.
The @scheme[for-each] procedure acts the most like a @tt{for} loop:
@interaction[
(for-each (lambda (elem)
(printf "I have ~a\n" elem))
(list "pie" "stew" "carrots and pizza, and pineapple, too"))
]
Scheme includes many other list-iteration procedures, because there
are multiple ways to combine the results from each iteration. The
@scheme[for-each] procedure completely ignores the per-element result,
so it is used with a loop body that has some side-effect (such as
printing output). The @scheme[map] procedure, in contrast, uses the
per-element results to create a new list:
@interaction[
(map sqrt (list 1 4 9 16))
(map (lambda (i)
(string-append i "!"))
(list "peanuts" "popcorn" "crackerjack"))
]
The @scheme[andmap] and @scheme[ormap] procedures combine the results
by @scheme[and]ing or @scheme[or]ing:
@interaction[
(andmap string? (list "a" "b" "c"))
(andmap string? (list "a" "b" 6))
(ormap number? (list "a" "b" 6))
]
The @scheme[for-each], @scheme[map], @scheme[andmap], and
@scheme[ormap] procedures can all handle multiple lists, instead of
just a single list. The lists must all have the same length, and the
given procedure must accept one argument for each list:
@interaction[
(map (lambda (s n) (substring s 0 n))
(list "peanuts" "popcorn" "crackerjack")
(list 6 3 7))
]
The @scheme[foldl] procedure generalizes some iteration procedures. It
uses the per-element procedure to both process an element and combine
it with the ``current'' value, so the per-element procedure takes an
extra first argument. Also, a starting ``current ' value must be
provided before the lists:
@interaction[
(foldl (lambda (v elem)
(+ v (* elem elem)))
0
'(1 2 3))
]
Despite its generality, @scheme[foldl] is not as popular as the other
procedures. The main reason is that @scheme[for-each], @scheme[map],
@scheme[ormap], and @scheme[andmap] cover the most common kinds of
loops.
@;------------------------------------------------------------------------
@section{Iterative Folds and Comprehensions: @scheme[fold-for] and @scheme[list-for]}
Besides iteration procedures like @scheme[foldl], Scheme provides a
syntactic form for iteration that more closely resembles the syntax of
other languages. The @scheme[foldl] example above can be written with
the @scheme[fold-for] syntax as follows:
@interaction[
(fold-for ([sum 0])
([elem (list 1 2 3)])
(+ sum elem))
]
Compare to analogous Java code, where @scheme[(list 1 2 3)] is
replaced by a collection @scheme[lst]:
@verbatim[
#<<EOS
int sum = 0;
for (Object elem : lst) {
sum = sum + elem;
}
return sum;
EOS
]
The only significant difference is that the updating of @scheme[sum]
and the return of @scheme[sum]'s value are implicit. Those implicit
actions are why the form is called @scheme[fold-for] instead of just
@scheme[for].
Along similar lines, the @scheme[list-for] form iterates through a list
and implicitly accumulates each result into a list:
@interaction[
(list-for ([i (list "peanuts" "popcorn" "crackerjack")])
(string-append i "!"))
]
The @scheme[list-for] form is a @defterm{list compherension} form, as
in Haskell, Ruby, Python, and other languages. Its advantage over
@scheme[map] is that it can iterate over more things than just lists.
For example, @scheme[list-for] can iterate over a range of numbers:
@interaction[
(list-for ([i (range 0 10)])
i)
]
The @scheme[list-for] form can even iterate over a list and a range of
numbers in parallel:
@interaction[
(list-for ([s (list "a" "b" "c")]
[n (range 0 3)])
(if (= n 2)
"oops!"
s))
]
Note that the binding syntax of @scheme[fold-for] and
@scheme[list-for] is similar to that of @scheme[let] (as introduced in
@secref["local-binding-intro"]). In the same way that @scheme[let*]
supports nested bindings, @scheme[list-for*] supports nested
iterations:
@interaction[
(list-for* ([s (list "a" "b" "c")]
[n (list "x" "y" "z")])
(string-append s n))
]
Unlike the @scheme[list-for], the nested iteration of
@scheme[list-for*] covers patterns with lists not as easily expressed
with @scheme[map]. When procedures like @scheme[map] suffice, however,
Scheme programmers tend to use them, partly because the syntax is
simpler (just a procedure call).
We have ignored several other variants of the interation
form---including plain @scheme[for], which is use when the iteration
body is to be run only for its effect. We explain the full set in
@secref["iterations+comprehensions"].
@;------------------------------------------------------------------------
@section{List Iteration from Scratch}
Although @scheme[map] and @scheme[list-for] are predefined, they are
not primitive in any interesting sense. You can write equivalent
iterations using just a handful of list primitives.
Since a Scheme list is a linked list, the two core operations on a
non-empty list are
@itemize{
@item{@scheme[first]: get the first thing in the list; and}
@item{@scheme[rest]: get the rest of the list.}
}
@examples[
(first (list 1 2 3))
(rest (list 1 2 3))
]
To create a new node for a linked list---that is, to add to the front
of the list---use the @scheme[cons] procedure, which is short for
``construct.'' To get an empty list to start with, use the
@scheme[empty] constant:
@interaction[
empty
(cons "head" empty)
(cons "dead" (cons "head" empty))
]
To process a list, you need to be able to distinguish empty lists from
non-empty lists, because @scheme[first] and @scheme[rest] work only on
non-empty lists. The @scheme[empty?] procedure detects empty lists,
and @scheme[cons?] detects non-empty lists (which pair an element with
another list):
@interaction[
(empty? empty)
(empty? (cons "head" empty))
(cons? empty)
(cons? (cons "head" empty))
]
With these pieces, you can write your own versions of the
@scheme[length] procedure, @scheme[map] procedure, and more.
@defexamples[
(define (my-length lst)
(cond
[(empty? lst) 0]
[else (+ 1 (my-length (rest lst)))]))
(my-length empty)
(my-length (list "a" "b" "c"))
]
@def+int[
(define (my-map f lst)
(cond
[(empty? lst) empty]
[else (cons (f (first lst))
(my-map f (rest lst)))]))
(my-map string-upcase (list "ready" "set" "go"))
]
If the definitions are mysterious to you, 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
@math{O(n)} time for a list of length @math{n}. This is easy to see by
imagining how @scheme[(my-length (list "a" "b" "c"))] must evaluate
sub-expression:
@schemeblock[
(my-length (list "a" "b" "c"))
#,step (+ 1 (my-length (list "b" "c")))
#,step (+ 1 (+ 1 (my-length (list "c"))))
#,step (+ 1 (+ 1 (+ 1 (my-length (list)))))
#,step (+ 1 (+ 1 (+ 1 0)))
#,step (+ 1 (+ 1 1))
#,step (+ 1 2)
#,step 3
]
For a list with @math{n} elements, evalution will stack up @math{n}
@scheme[(+ 1 ...)] additions, and then finally add them up when the
list is exhausted. You can avoid piling up additions by adding along
the way, accumulating the length in a variable @scheme[len].
@schemeblock[
(define (my-length lst)
(code:comment #, @elem{local procedure @scheme[iter]:})
(define (iter lst len)
(cond
[(empty? lst) len]
[else (iter (rest lst) (+ len 1))]))
(code:comment #, @elem{body of @scheme[my-length] calls @scheme[iter]:})
(iter lst 0))
]
Now evaluation looks like this:
@schemeblock[
(my-length (list "a" "b" "c"))
#,step (iter (list "a" "b" "c") 0)
#,step (iter (list "b" "c") 1)
#,step (iter (list "c") 2)
#,step (iter (list) 3)
3
]
The revised @scheme[my-length] runs in constant space, just as the
evaluation steps above suggest. That is, when the result of a
procedure call is the result of some other procedure call, then the
original procedure doesn't have to wait around for the result, taking
up space for no good reason. This evaluation behavior is sometimes
called @idefterm{tail-call optimization}, but it's not merely an
``optimization'' in Scheme; it's a guarantee about the way the code
will run.
In the case of @scheme[my-map], @math{O(n)} space compelxity is
reasonable, since it has to generate an @math{O(n)}
result. Nevertheless, you can reduce the constant factor by
accumulating the result list. The only catch is that the accumulated
list will be backwards, so you'll have to reverse it at the very end:
@schemeblock[
(define (my-map f lst)
(define (iter lst backward-result)
(cond
[(empty? lst) (reverse backward-result)]
[else (iter (rest lst)
(cons (f (first lst))
backward-result))]))
(iter lst empty))
]
It turns out that if you write
@schemeblock[
(define (my-map f lst)
(list-for ([i lst])
(f i)))
]
then the @scheme[list-for] form in the procedure both is expanded to
essentially the same code as the @scheme[iter] local definition and
use. The difference is merely syntactic convenience.
@;------------------------------------------------------------------------
@section{Recursion versus Iteration}
The @scheme[my-length] and @scheme[my-map] examples demonstrate that
iteration is just a special case of recursion. In many languages, it
is important to try to fit as many computations as possible into
iteration form, otherwise performance will be bad and moderately large
inputs can lead to stack overflow. Similarly, in Scheme, it is often
important to make sure that tail recursion is used to avoid
@math{O(n)} space consumption when the computation is easily performed
in constant space.
At the same time, recursion does not lead to particularly bad
performance in Scheme, and there is no such thing as stack overflow;
you can run out of memory if a computation involves too much context,
but exhausting memory typically requires orders of magnitude deeper
recursion than would trigger a stack overflow in other
languages. These considerations, combined with the fact that
tail-recursive programs automatically run the same as a loop, lead
Scheme programmers to embrace recursive forms rather than avoid them.
Suppose, for example, that you want to remove consecutive duplicates
from a list. While that can be written as a loop that remembers the
previous element for each iteration, a Scheme programmer would more
likely just write the following:
@def+int[
(define (remove-dups l)
(cond
[(empty? l) empty]
[(empty? (rest l)) l]
[(equal? (first l) (first (rest l))) (remove-dups (rest l))]
[else (cons (first l)
(remove-dups (rest l)))]))
(remove-dups (list "a" "b" "b" "b" "c" "c"))
]
In general, this procedure consumes @math{O(n)} space for an input
list of length @math{n}, but that's fine, since it produces an
@math{O(n)} result. If the input list happens to be mostly consecutive
duplicates, then the resulting list can be much smaller than
@math{O(n)}---and @scheme[remove-dups] will also use much less than
@math{O(n)} space! The reason is that the third case in the
@scheme[cond], which discards duplicates, returns the result of a
@scheme[remove-dups] call directly, so the tail-call ``optimization''
kicks in:
@schemeblock[
(remove-dups (list "a" "b" "b" "b" "b" "b"))
#,step (cons "a" (remove-dups (list "b" "b" "b" "b" "b")))
#,step (cons "a" (remove-dups (list "b" "b" "b" "b")))
#,step (cons "a" (remove-dups (list "b" "b" "b")))
#,step (cons "a" (remove-dups (list "b" "b")))
#,step (cons "a" (remove-dups (list "b")))
#,step (cons "a" (list "b"))
#,step (list "a" "b")
]
Tail-call behavior becomes even more important when dealing with
non-list data and when using an object-oriented style. In the latter
case, an object must frequently dispatch to another object; if the
other object's result is the complete answer, there's no reason for
the first object to wait around. We defer this extended discussion
until @secref["datatypes"], at which point we'll have more forms of
data to consider.
@;------------------------------------------------------------------------
@section{Named @scheme[let]}
As you start reading Scheme code, you'll discover one more form that
is commonly used to implement recursive functions: @idefterm{named @scheme[let]}.
A named @scheme[let] uses the same syntactic keyword as a simple
sequence of local bindings, but an @nonterm{identifier} after the
@scheme[let] (instead of an immediate open parenthesis) triggers a
different parsing. In general,
@schemeblock[
#, @BNF-seq[@litchar{(} @litchar{let} @nonterm{proc-identifier} @litchar{(}
@kleenestar{@BNF-group[@litchar{[} @nonterm{arg-identifier} @nonterm{init-expression} @litchar{]}]}
@litchar{)}
@kleeneplus{@nonterm{body-expression}} @litchar{)}]
]
is equivalent to the sequence
@schemeblock[
#, @BNF-seq[@litchar{(}@litchar{define} @litchar{(} @nonterm{proc-identifier} @kleenestar{@nonterm{arg-identifier}} @litchar{)}
@kleeneplus{@nonterm{body-expression}} @litchar{)}]
#, @BNF-seq[@litchar{(}@nonterm{proc-identifier} @kleenestar{@nonterm{init-expression}}@litchar{)}]
]
except that the @scheme[let] form works in any expression
context.
That is, a named @scheme[let] binds a procedure identifier that is
visible only in the procedure's body, and it implicitly calls the
procedure with the values of some initial expressions. It looks
similar to the start of @scheme[fold-for], but the recursive calls in
the body are explicit, and they are not constrained to tail position.
As an example, here is @scheme[my-map] once again, using a named let
to bind the local @scheme[iter] procedure:
@schemeblock[
(define (my-map f lst)
(let iter ([lst lst]
[backward-result empty])
(cond
[(empty? lst) (reverse backward-result)]
[else (iter (rest lst)
(cons (f (first lst))
backward-result))])))
]
Here's another example, where the local @scheme[dup] procedure is used
recursively and not merely iteratively, and where the traversal of a
list stops part-way:
@def+int[
(define (duplicate pos lst)
(let dup ([i 0]
[lst lst])
(cond
[(= i pos) (cons (first lst) lst)]
[else (cons (first lst) (dup (+ i 1) (rest lst)))])))
(duplicate 1 (list "apple" "cheese burger!" "banana"))
]

View File

@ -0,0 +1,6 @@
@title{Parsing Programs and Data}
The set of syntactic forms and even lexem syntax for a Scheme program
is extensible, so a conventional BNF grammar cannot capture the
grammar of Scheme.

View File

@ -0,0 +1,670 @@
#reader(lib "docreader.ss" "scribble")
@require[(lib "manual.ss" "scribble")]
@require[(lib "eval.ss" "scribble")]
@require[(lib "bnf.ss" "scribble")]
@require["guide-utils.ss"]
@title[#:tag "syntax-overview"]{Just Enough Scheme Syntax}
The syntax of a Scheme program is specified in an unusual way compared
to most programming languages. In particular, importing a module can
introduce new definition and expression forms, so the syntax of a
Scheme module cannot be written as a context-free grammar. Even more
radically, the language name after @schemefont{#module} determines the
token-level syntax of the code that follows it.
As a starting point, however, we can pretend that Scheme's syntax
follows a context-free grammar. We'll start with this approximation,
and work from there to build up a more complete picture of the
language.
The following BNF grammar sketches a simplified syntax for Scheme.
Text with a gray background, such as @litchar{#module}, represents
literal text. Whitespace must appear between separate such literals
and nonterminals like @nonterm{identifier}, except that whitespace is
not required before or after @litchar{(}, @litchar{)}, @litchar{[}, or
@litchar{]}. Following the usual conventions, @kleenestar{} means
zero or more repetitions of the preceding element, @kleeneplus{} means
one or more repetitions of the preceding element, and @BNF-group{}
groups a sequence as an element for repetition.
@define[val-defn-stx @BNF-seq[@litchar{(}@litchar{define} @nonterm{identifier} @nonterm{expression} @litchar{)}]]
@define[fun-defn-stx
@BNF-seq[@litchar{(}@litchar{define} @litchar{(} @nonterm{identifier} @kleenestar{@nonterm{identifier}} @litchar{)}
@kleeneplus{@nonterm{expression}} @litchar{)}]]
@define[fun-defn2-stx
@BNF-seq[@litchar{(}@litchar{define} @litchar{(} @nonterm{identifier} @kleenestar{@nonterm{identifier}} @litchar{)}
@kleenestar{@nonterm{definition}} @kleeneplus{@nonterm{expression}} @litchar{)}]]
@define[app-expr-stx @BNF-seq[@litchar{(} @nonterm{identifier} @kleenestar{@nonterm{expression}} @litchar{)}]]
@define[app2-expr-stx @BNF-seq[@litchar{(} @nonterm{expression} @kleenestar{@nonterm{expression}} @litchar{)}]]
@define[if-expr-stx @BNF-seq[@litchar{(} @litchar{if} @nonterm{expression} @nonterm{expression} @nonterm{expression} @litchar{)}]]
@define[lambda-expr-stx @BNF-seq[@litchar{(} @litchar{lambda} @litchar{(} @kleenestar{@nonterm{identifier}} @litchar{)}
@kleeneplus{@nonterm{expression}} @litchar{)}]]
@define[lambda2-expr-stx
@BNF-seq[@litchar{(} @litchar{lambda} @litchar{(} @kleenestar{@nonterm{identifier}} @litchar{)}
@kleenestar{@nonterm{definition}} @kleeneplus{@nonterm{expression}} @litchar{)}]]
@define[and-expr-stx @BNF-seq[@litchar{(} @litchar{and} @kleenestar{@nonterm{expression}} @litchar{)}]]
@define[or-expr-stx @BNF-seq[@litchar{(} @litchar{or} @kleenestar{@nonterm{expression}} @litchar{)}]]
@define[cond-expr-stx @BNF-seq[@litchar{(} @litchar{cond}
@kleenestar{@BNF-group[@litchar{[} @nonterm{expression} @nonterm{expression} @litchar{]}]}
@litchar{)}]]
@define[(make-let-expr-stx kw)
@BNF-seq[@litchar{(} kw @litchar{(}
@kleenestar{@BNF-group[@litchar{[} @nonterm{identifier} @nonterm{expression} @litchar{]}]}
@litchar{)}
@kleeneplus{@nonterm{expression}} @litchar{)}]]
@define[let-expr-stx (make-let-expr-stx @litchar{let})]
@define[let*-expr-stx (make-let-expr-stx @litchar{let*})]
@BNF[(list @nonterm{module} @BNF-seq[@litchar{#module} @nonterm{langname} @kleenestar{@nonterm{topform}}])
(list @nonterm{topform} @nonterm{definition}
@nonterm{expression}
@BNF-etc)
(list @nonterm{definition} val-defn-stx
fun-defn-stx
@BNF-etc)
(list @nonterm{expression} @nonterm{identifier}
@nonterm{constant}
app-expr-stx
if-expr-stx
lambda-expr-stx
let-expr-stx
let*-expr-stx
@BNF-etc)]
The syntax for comments, which are are treated the same as whitespace,
is not shown in the grammar above. A comment starts with @litchar{;}
and runs until the end of the line.
The REPL evaluates @nonterm{topform}s, just like the body of a module.
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@section{Definitions}
A definition of the form
@schemeblock[#, @val-defn-stx]
binds @nonterm{identifier} to the result of @nonterm{expression}, while
@schemeblock[#, @fun-defn-stx]
binds the first @nonterm{identifier} to a procedure that takes
arguments as named by the remaining @nonterm{identifier}s. The
@nonterm{expression}s are the body of the procedure. When called, the
procedure returns the result of the last @nonterm{expression}.
@defexamples[
(code:line (define five 5) (code:comment #, @t{defines @scheme[five] to be @scheme[5]}))
(define (piece str) (code:comment #, @t{defines @scheme[piece] as a procedure of one argument})
(substring str 0 five))
five
(piece "hello world")
]
Under the hood, a procedure definition is really the same as a
non-procedure definition. Consequently, a procedure name does not have to be
used in a procedure call. A procedure is just another kind of value,
though the printed form is necessarily less complete than the printed
form of a number or string.
@examples[
piece
substring
]
Within a module, each definition must bind a distinct
@nonterm{identifier}, and only identifiers with no imported bindings
can be defined. A definition in the REPL, in contrast, overwrites any
previous definition for the same @nonterm{identifier}.
@examples[
(define five 5)
(substring "hello world" 0 five)
(define five 8)
(substring "hello world" 0 five)
]
A procedure definition can include multiple expressions for the
procedure's body. In that case, only the value of the last expression
is returned when the procedure is called. The other expressions are
evaluated only for some side-effect, such as printing.
@defexamples[
(define (greet name)
(printf "returning a greeting for ~a...\n" name)
(string-append "hello " name))
(greet "universe")
]
Although you should generally avoid side-effects, it's important to
understand that multiple expressions are allowed in a definition
body. It explains why the following @scheme[nogreet] procedure simply
returns its argument:
@def+int[
(define (nogreet name)
string-append "hello " name)
(nogreet "world")
]
There are no parentheses around @scheme[string-append "hello " name],
so they are three separate expressions instead of one procedure-call
expression. The expressions @scheme[string-append] and
@scheme["hello "] are evaluated, but the results are never
used. Instead, the result of the procedure is just the result of
the expression @scheme[name].
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@section{Identifiers}
Scheme's syntax for identifiers is especially liberal. Excluding the
special characters
@t{
@hspace[2] @litchar{(} @litchar{)} @litchar{[} @litchar{]}
@litchar["{"] @litchar["}"]
@litchar{"} @litchar{,} @litchar{'} @litchar{`}
@litchar{;} @litchar{#}
}
and except for the sequences of characters that make number constants,
almost any sequence of non-whitespace characters forms an
@nonterm{identifier}. For example @schemeid[substring] is an
identifier. Also, @schemeid[string-append] and @schemeid[a+b] are
identifiers, as opposed to arithmetic expressions. Here are several
more examples:
@schemeblock[
#, @schemeid[+]
#, @schemeid[Apple]
#, @schemeid[integer?]
#, @schemeid[call/cc]
#, @schemeid[call-with-composable-continuation]
#, @schemeid[x-1+3i]
#, @schemeid[define]
]
Since @schemeid[define] is itself an identifier, you could
re-define @schemeid[define] in the REPL. That's rarely a good idea,
of course, and it's not allowed in any module where
@scheme[define] already has a meaning.
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@section{Constants}
Scheme constants include numbers, booleans, strings, and byte
strings. In documentation examples and in DrScheme, constant
expressions are shown in green.
@defterm{Numbers} are written in the usual way, including fractions
and imagnary numbers. Numbers that use decimal points or exponent
markers are implemented as double-precision floating-point numbers,
and they are called @defterm{inexact} numbers in Scheme
terminology. Other numbers are implemented as @defterm{exact} with
arbitrary precision. In the example number constants below, the ones
on the left are exact, and the ones on the right are inexact
approximations:
@schemeblock[
1 1.0
1/2 0.5
1+2i 1.0+2i
9999999999999999999999 1e+22
]
@defterm{Booleans} are @scheme[#t] for true and @scheme[#f] for
false. In conditionals, however, all non-@scheme[#f] values are
treated as true.
@defterm{Strings} are written between double quotes. Within a string,
backslash is an escaping character; for example, a backslash followed
by a double-quote includes a little double-quote in the string. Except
for an unescaped double-quote or backslash, any Unicode character can
appear in a string constant.
@schemeblock[
"hello world"
"A \"fancy\" string"
"\u03BBx:(\u03BC\u03B1.\u03B1\u2192\u03B1).xx"
]
When a constant is evaluated in the REPL, it typically prints the same
as its input syntax. In same cases, the printed form is a normalized
version of the input syntax. In other cases, the printed result of an
expression does not correspond to input syntax at all, such as when an
expression proceduces a procedure (instead of applying the
procedure). In documentation and in DrScheme's REPL, results are
printed in blue instead of green to highlight the difference between
an input expression and a printed result.
@examples[
(eval-example-string "1.0000")
(eval-example-string "\"A \\u0022fancy\\u0022 string\"")
string-append
]
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@section{Procedure Applications}
We have already seen many procedure calls---or @defterm{procedure
applications} in Scheme termonology. The syntax of a procedure
call is
@schemeblock[
#, app-expr-stx
]
where the number of @nonterm{expression}s determines the number of
arguments supplied to the procedure named by @nonterm{identifier}.
The @schememodname[big] language pre-defines many procedure
identifiers, such as @scheme[substring] and
@scheme[string-append]. More examples are below.
In example Scheme code throughout the documentation, uses of
pre-defined names are hyperlinked to the reference manual. So, you can
click on an identifier to get full details about its use.
@interaction[
(code:line (string-append "hello" " " "scheme") (code:comment #, @t{append any number of strings}))
(code:line (substring "hello scheme" 6 12) (code:comment #, @t{extract a substring}))
(code:line (string-length "scheme") (code:comment #, @t{get a string's length}))
(code:line (string? "hello scheme") (code:comment #, @t{recognize strings}))
(string? 1)
(code:line (sqrt 16) (code:comment #, @t{find a square root}))
(sqrt -16)
(code:line (+ 1 2) (code:comment #, @t{add numbers}))
(code:line (- 2 1) (code:comment #, @t{subtract numbers}))
(code:line (< 2 1) (code:comment #, @t{compare numbers}))
(>= 2 1)
(code:line (number? "hello scheme") (code:comment #, @t{recognize numbers}))
(number? 1)
(code:line (equal? 1 "hello") (code:comment #, @t{compare anything}))
(equal? 1 1)
]
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@section{Conditionals with @scheme[if], @scheme[and], @scheme[or], and @scheme[cond]}
After identifiers and constants, the next simplest kind of expression
is an @scheme[if] conditional:
@schemeblock[
#, if-expr-stx
]
The first @nonterm{expression} is always evaluted. If it produces a
non-@scheme[#f] value, then the second @nonterm{expression} is
evaluted for the result of the whole @scheme[if] expression, otherwise
the third @nonterm{expression} is evaluated for the result.
The @scheme[if] form is often used with procedures whose names end in
@schemeid[?]:
@interaction[
(if (> 2 3)
"bigger"
"smaller")
]
@def+int[
(define (reply s)
(if (equal? "hello" (substring s 0 5))
"hi!"
"huh?"))
(reply "hello scheme")
(reply "\u03BBx:(\u03BC\u03B1.\u03B1\u2192\u03B1).xx")
]
More complex conditionals can be formed by nesting @scheme[if]
expressions. For example, you could make the @scheme[reply] procedure
work when given non-strings:
@schemeblock[
(define (reply s)
(if (string? s)
(if (equal? "hello" (substring s 0 5)
"hi!"
"huh?"))
"huh?"))
]
Instead of duplicating the @scheme["huh?"] case, this procedure is
better written as
@schemeblock[
(define (reply s)
(if (if (string? s)
(equal? "hello" (substring s 0 5)
#f))
"hi!"
"huh?"))
]
but these kinds of nested @scheme[if]s are difficult to read. Scheme
provides a more readable shortcut through the @scheme[and] and
@scheme[or] forms, which work with any number of expressions:
@schemeblock[
#, and-expr-stx
#, or-expr-stx
]
The @scheme[and] form short-circuits: it stops and returns @scheme[#f]
when and expression produces @scheme[#f], otherwise it keeps
going. The @scheme[or] form similarly short-circuits when it
encounters a true result.
@defexamples[
(define (reply s)
(if (and (string? s)
(>= (string-length s) 5)
(equal? "hello" (substring s 0 5)))
"hi!"
"huh?"))
(reply "hello scheme")
(reply 17)
]
Another common pattern of nested @scheme[if]s involves a sequence of
tests, each with its own result:
@schemeblock[
(define (reply-more s)
(if (equal? "hello" (substring s 0 5))
"hi!"
(if (equal? "goodbye" (substring s 0 7))
"bye!"
(if (equal? "?" (substring s (- (string-length s) 1)))
"I don't know"
"huh?"))))
]
The shorthand for a sequence of tests is the @scheme[cond] form:
@schemeblock[
#, cond-expr-stx
]
A @scheme[cond] form contains a sequence of clauses between square
brackets. In each clause, the first @nonterm{expression} is a test
expression. If it produces true, then the clause's second
@nonterm{expression} provides the answer for the entire @scheme[cond]
expression, and the rest of the clauses are ignored. If the test
@nonterm{expression} produces @scheme[#f], then the clause's second
@nonterm{expression} is ignored, and evaluation continues with the
next clause. The last clause can use @scheme[else] as a sononym for
@scheme[#t] in place of a test expression.
Using @scheme[cond], the @scheme[reply-more] procedure can be more
clearly written as follows:
@def+int[
(define (reply-more s)
(cond
[(equal? "hello" (substring s 0 5))
"hi!"]
[(equal? "goodbye" (substring s 0 7))
"bye!"]
[(equal? "?" (substring s (- (string-length s) 1)))
"I don't know"]
[else "huh?"]))
(reply-more "hello scheme")
(reply-more "goodbye cruel world")
(reply-more "what is the airspeed velocity of an unladen swallow?")
(reply-more "but I like the cookie!")
]
The use of square brackets for @scheme[cond] clauses is a
convention. In Scheme, parentheses and square brackets are actually
interchangable, as long as @litchar{(} is matched with @litchar{)} and
@litchar{[} is matched with @litchar{]}. Using square brackets in a
few key places makes Scheme code even more readable.
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@section{Procedure Applications, Again}
In our pretend grammar of Scheme, we oversimplified in the description
of procedure applications. The actual syntax of a procedure
application allows an arbitrary expression for the procedure, instead
of just an @nonterm{identifier}:
@schemeblock[
#, app2-expr-stx
]
The first @nonterm{expression} is often an @nonterm{identifier}, such
as @scheme[string-append] or @scheme[+], but it can be anything that
evaluates to an procedure. For example, it can be a conditional
expression:
@def+int[
(define (double v)
((if (string? v) string-append +) v v))
(double "hello")
(double 5)
]
Syntactically, the first expression in a procedure application could
even be a number---but that leads to an error, since a number is not a
procedure.
@interaction[(1 2 3 4)]
When you accidentally omit a procedure name or when you use
parentheses around an expression, you'll most often get an ``expected
a procedure'' error like this one.
Technically, @scheme[(if #t 1 2)] can be parsed as a procedure
application as well as a conditional in our pretend grammar of Scheme,
since @schemeid[if] is an identifier. For now, we say that the
application form has a weaker precedence than the other forms, and
we'll leave a full explanation to our discussion of
@secref["scheme-forms"].
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@section{Anonymous Procedures with @scheme[lambda]}
Programming in Scheme would be tedious if you had to name all of your
numbers. Instead of writing @scheme[(+ 1 2)], you'd have to write
@interaction[
(define a 1)
(define b 2)
(+ a b)
]
It turns out that having to name all your procedures can be tedious,
too. For example, you might have a procedure @scheme[twice] that takes
a procedure and an argument. Using @scheme[twice] is convenient if you
already have a name for the procedure, such as @scheme[sqrt]:
@def+int[
(define (twice f v)
(f (f v)))
(twice sqrt 16)
]
If you want to apply a procedure that is not yet defined, you could
define it, and then pass it to @scheme[twice]:
@def+int[
(define (louder s)
(string-append s "!"))
(twice louder "hello")
]
But if the call to @scheme[twice] is the only place where
@scheme[louder] is used, it's a shame to have to write a whole
definition. In Scheme, you can use a @scheme[lambda] expression to
produce a procedure directly. The @scheme[lambda] form is followed by
identifiers for the procedure's arguments, and then the procedure's
body expressions:
@schemeblock[
#, lambda-expr-stx
]
Evaluating a @scheme[lambda] form by itself produces a procedure:
@interaction[(lambda (s) (string-append s "!"))]
Using @scheme[lambda], the above call to @scheme[twice] can be
re-written as
@interaction[
(twice (lambda (s) (string-append s "!"))
"hello")
(twice (lambda (s) (string-append s "?!"))
"hello")
]
Another use of @scheme[lambda] is as a result for a procedure that
generates procedures:
@def+int[
(define (make-add-suffix s2)
(lambda (s) (string-append s s2)))
(twice (make-add-suffix "!") "hello")
(twice (make-add-suffix "?!") "hello")
(twice (make-add-suffix "...") "hello")
]
Scheme is a @defterm{lexically scoped} language, which means that
@scheme[s2] in the procedure returned by @scheme[make-add-suffix]
always refers to the argument for the call that created the
procedure. In other words, the @scheme[lambda]-generated procedure
``remembers'' the right @scheme[s2]:
@interaction[
(define louder (make-add-suffix "!"))
(define less-sure (make-add-suffix "?"))
(twice less-sure "yeah")
(twice louder "yeah")
]
We have so far referred to definitions of the form @scheme[(define #,
@nonterm{identifier} #, @nonterm{expression})] as ``non-procedure
definitions.'' This characterization is misleading, because the
@nonterm{expression} could be a @scheme[lambda] form, in which case
the definition is equivalent to using the ``procedure'' definition
form. For example, the following two definitions of @scheme[louder]
are equivalent:
@defs+int[
[(define (louder s)
(string-append s "!"))
code:blank
(define louder
(lambda (s)
(string-append s "!")))]
louder
]
Note that the expression for @scheme[louder] in the second case is an
``anonymous'' procedure written with @scheme[lambda], but the compiler
infers a name, anyway, for the purpose of printing the procedure.
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@section[#:tag "local-binding-intro"]{Local Binding with with
@scheme[define], @scheme[let], and @scheme[let*]}
It's time to retract another simplification in our pretend grammar of
Scheme. In the body of a procedure, definitions can appear before the
body expressions:
@schemeblock[
#, fun-defn2-stx
#, lambda2-expr-stx
]
Definitions at the start of a procedure body are local to the
procedure body.
@defexamples[
(define (converse s)
(define (starts? s2) (code:comment #, @t{local to @scheme[converse]})
(define len2 (string-length s2)) (code:comment #, @t{local to @scheme[starts?]})
(and (>= (string-length s) len2)
(equal? s2 (substring s 0 len2))))
(cond
[(starts? "hello") "hi!"]
[(starts? "goodbye") "bye!"]
[else "huh?"]))
(converse "hello!")
(converse "urp")
(code:line starts? (code:comment #, @t{outside of @scheme[converse], so...}))
]
Another way to create local bindings is the @scheme[let] form. An
advantage of @scheme[let] is that it can be used in any expression
position. Also, @scheme[let] binds many identifiers at once, instead
of requiring a separate @scheme[define] for each identifier.
@schemeblock[
#, let-expr-stx
]
Each binding clause is an @nonterm{identifier} and a
@nonterm{expression} surrounded by square brackets, and the
expressions after the clauses are the body of the @scheme[let]. In
each clause, the @nonterm{identifier} is bound to the result of the
@nonterm{expression} for use in the body.
@interaction[
(let ([x 1]
[y 2])
(format "adding ~s and ~s produces ~s" x y (+ x y)))
]
The bindings of a @scheme[let] form are available only in the body of
the @scheme[let], so the binding clauses cannot refer to each
other. The @scheme[let*] form, in contrast, allows later clauses to
use earlier bindings:
@interaction[
(let* ([x 1]
[y 2]
[z (+ x y)])
(format "adding ~s and ~s produces ~s" x y z))
]
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@section{The Language So Far}
As you saw, the little grammar that we showed at the
@seclink["syntax-overview"]{beginning} of the chapter turned out to be
too simple even for this chapter. Here's the grammar that we have now:
@BNF[(list @nonterm{module} @BNF-seq[@litchar{#module} @nonterm{langname} @kleenestar{@nonterm{topform}}])
(list @nonterm{topform} @nonterm{definition}
@nonterm{expression}
@BNF-etc)
(list @nonterm{definition} val-defn-stx
fun-defn2-stx
@BNF-etc)
(list @nonterm{expression} @nonterm{identifier}
@nonterm{constant}
app2-expr-stx
if-expr-stx
or-expr-stx
and-expr-stx
cond-expr-stx
lambda2-expr-stx
let-expr-stx
let*-expr-stx
@BNF-etc)]
For an expanded grammar, it's still a pretty small language! This
language is plenty, however, to write lots of interesting programs.
Depending on your programming background, you may be struck by the
apparent absence of an iteration form. But the above is enough to
write any kind of loop, as we see in the next chapter. Moreover, an
extra built-in datatype (to go along numbers, strings, etc.) gives us
more interesting data to process with loops. The new datatype is also
the key to understanding the true syntax of Scheme, which we get back
to in @secref["scheme-read"] and @secref["scheme-forms"].

View File

@ -0,0 +1,280 @@
#reader(lib "docreader.ss" "scribble")
@require[(lib "manual.ss" "scribble")]
@require[(lib "eval.ss" "scribble")]
@require["guide-utils.ss"]
@interaction-eval[(require (lib "list.ss"))]
@title{The Truth about Pairs, Lists, and Scheme Syntax}
The @scheme[cons] procedure actually accepts any two values, not just
a list for the second argument. When the second argument is not
@scheme[empty] or itself produced by @scheme[cons], the result prints
in a special way. The two values joined with @scheme[cons] are printed
between parentheses, but with a dot (i.e., a period surrounded by
whitespace) in between:
@interaction[(cons 1 2) (cons "banana" "split")]
Thus, a value produced by @scheme[cons] is not always a list. In
general, the result of @scheme[cons] is a @defterm{pair}. The more
traditional name for the @scheme[cons?] procedure is @scheme[pair?],
and we'll use the traditional name from now on.
The name @scheme[rest] also makes less sense for non-list pairs; the
more traditional names for @scheme[first] and @scheme[rest] are
@scheme[car] and @scheme[cdr], respectively. (Granted, the traditional
names are also nonsense. Just remember that ``a'' comes before ``d,''
and @scheme[cdr] is pronounced ``could-er.'')
@examples[
(car (cons 1 2))
(cdr (cons 1 2))
(pair? empty)
(pair? (cons 1 2))
(pair? (list 1 2 3))
]
Scheme's pair datatype and its relation to lists is essentially a
historical curiosity, along with the dot notation for printing and the
funny names @scheme[car] and @scheme[cdr]. Pairs are deeply wired into
to the culture, specification, and implementation of Scheme, however,
so they survive in the language.
You are perhaps most likely to encounter a non-list pair when making a
mistake, such as accidentally reversing the arguments to
@scheme[cons]:
@interaction[(cons (list 2 3) 1) (cons 1 (list 2 3))]
Non-list pairs are used intentionally, sometimes. For example, the
@scheme[make-immutable-hash-table] procedure takes a list of pairs,
where the @scheme[car] of each pair is a key and the @scheme[cdr] is a
value.
The only thing more confusing to new Schemers than non-list pairs is
the printing convention for pairs where the second element @italic{is}
a pair, but @italic{is not} a list:
@interaction[(cons 0 (cons 1 2))]
In general, the rule for printing a pair is as follows: use the dot
notation always, but if the dot is immediately followed by an open
parenthesis, then remove the dot, the open parenthesis, and the
matching close parenthesis. Thus, @schemeresultfont{(0 . (1 . 2))}
becomes @schemeresult[(0 1 . 2)], and
@schemeresultfont{(1 . (2 . (3 . ())))} becomes @schemeresult[(1 2 3)].
@;------------------------------------------------------------------------
@section{Quoting Lists and Symbols with @scheme[quote]}
After you see
@interaction[
(list 1 2 3)
]
enough times, you'll wish (or you're already wishing) that there was a
way to write just @scheme[(1 2 3)] and have it mean the list that
prints as @schemeresult[(1 2 3)]. The @scheme[quote] form does exactly
that:
@interaction[
(eval:alts (#, @scheme[quote] (1 2 3)) '(1 2 3))
(eval:alts (#, @scheme[quote] ("red" "green" "blue")) '("red" "green" "blue"))
(eval:alts (#, @scheme[quote] ()) '())
]
The @scheme[quote] form works with the dot notation, too, whether the
quoted form is normalized by the dot-parenthesis elimination rule or
not:
@interaction[
(eval:alts (#, @scheme[quote] (1 . 2)) '(1 . 2))
(eval:alts (#, @scheme[quote] (0 #, @schemeparenfont{.} (1 . 2))) '(0 . (1 . 2)))
]
Naturaly, lists can be nested:
@interaction[
(list (list 1 2 3) 5 (list "a" "b" "c"))
(eval:alts (#, @scheme[quote] ((1 2 3) 5 ("a" "b" "c"))) '((1 2 3) 5 ("a" "b" "c")))
]
If you wrap an identifier with @scheme[quote], then you get output
that looks like an identifier:
@interaction[
(eval:alts (#, @scheme[quote] jane-doe) 'jane-doe)
]
A value that prints like an identifier is a @defterm{symbol}. In the
same way that parentehsized output should not be confused with
expressions, a printed symbol should not be confused with an
identifier. In particular, the symbol @scheme[(#, @scheme[quote] #,
@schemeidfont{map})] has nothing to do with the @schemeidfont{map}
identifier or the predefined function that is bound to
@schemeidfont{map}, except that the symbol and the identifier happen
to be made up of the same letters.
Indeed, the intrinsic value of a symbol is nothing more than its
character content. In this sense, symbols and strings are almost the
same thing, and the main difference is how they print. The procedures
@scheme[symbol->string] and @scheme[string->symbol] convert between
them.
@examples[
map
(eval:alts (#, @scheme[quote] #, @schemeidfont{map}) 'map)
(eval:alts (symbol? (#, @scheme[quote] #, @schemeidfont{map})) (symbol? 'map))
(symbol? map)
(procedure? map)
(string->symbol "map")
(eval:alts (symbol->string (#, @scheme[quote] #, @schemeidfont{map})) (symbol->string 'map))
]
Naturally, when @scheme[quote] is used on a parenthesized sequence of
identifiers, it creates a list of symbols:
@interaction[
(eval:alts (#, @scheme[quote] (#, @schemeidfont{road} #, @schemeidfont{map})) '(road map))
(eval:alts (car (#, @scheme[quote] (#, @schemeidfont{road} #, @schemeidfont{map}))) (car '(road map)))
(eval:alts (symbol? (car (#, @scheme[quote] (#, @schemeidfont{road} #, @schemeidfont{map})))) (symbol? (car '(road map))))
]
@;------------------------------------------------------------------------
@section{Abbreviating @scheme[quote] with @schemevalfont{'}}
If @scheme[(#, @scheme[quote] (1 2 3))] is still too much typing, you
can abbreviate by just putting @litchar{'} in front of @scheme[(1 2
3)]:
@interaction[
'(1 2 3)
'road
'((1 2 3) road ("a" "b" "c"))
]
In the documentation, @litchar{'} is printed in green along with the
form after it, since the combination is an expression that is a
constant. In DrScheme, only the @litchar{'} is colored green. DrScheme
is more precisely correct, because the meaning of @scheme[quote] can
vary depending on the context of an expression. In the documentation,
however, we routinely assume that standard bindings are in scope, and
so we paint quoted forms in green for extra clarity.
A @litchar{'} expands to a @scheme[quote] form in quite a literal
way. You can see this if you put a quote in front of a form that has a
quote:
@interaction[
(eval:alts (car '(#, @schemevalfont{quote} #, @schemevalfont{road})) 'quote)
(car ''road)
]
Beware, however, that the REPL's printer recognizes the symbol
@schemeidfont{quote} hwne printing output, and it uses @schemeidfont{'}
in the output:
@interaction[
'road
''road
(eval:alts '(#, @schemevalfont{quote} #, @schemevalfont{road}) ''road)
]
There is a method to this madness. It has to do with the true nature
of Scheme syntax (which we discuss in the next section) and the
traditional Lisp approach to meta-programming (which we discuss in the
@seclink["quote-eval"]{section afterward}).
@;------------------------------------------------------------------------
@section{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
we have been simplifying Scheme's true syntax.
The syntax of Scheme is not defined directly in terms of character
streams. Instead, the syntax is determined by two layers:
@itemize{
@item{a @defterm{read} layer, which turns a sequence of characters
into a lists, symbols, and other constants; and}
@item{an @defterm{expand} layer, which processes the lists, symbols,
and other constants to parse them as an expression.}
}
The rules for printing and the read layer go together. For example, a
list is printed with parentheses, and reading a pair of parentheses
produces a list. Similarly, a non-list pair is printed with the dot
notation, and a dot on input effectively runs the dot-notation rules
in reverse to obtain a pair.
One consequence of the read layer for expressions is that you can use
the dot notation in expressions that are not quoted forms:
@interaction[
(eval:alts (+ 1 . #, @scheme[(2)]) (+ 1 2))
]
This works because @scheme[(+ 1 . #, @scheme[(2)])] is just another
way of writing @scheme[(+ 1 2)]. Of course, it is practically never a
good idea to write application expressions using this dot notation.
The rule for converting @litchar{'} to a use of @scheme[quote] is also
defined at the read level. If you (accidentally) use
@schemeidfont{quote} as an identifier, the result makes sense only
when you understand the reader's conversion:
@def+int[
(define (shakespeare quot)
(list 'shakespeare 'says quot))
(shakespeare "to be or not to be")]
@schemeblock[
(define (shakey #, @schemeidfont{quote})
(list '#, @schemeidfont{shakey} '#, @schemeidfont{says} #, @schemeidfont{quote}))
]
@interaction[
(eval:alts (shakey "to be or not to be") (let ([shakey (lambda (x) x)]) ("to be or not to be" shakey)))
]
The second example fails because @scheme['#, @schemeidfont{shakey}] is
really @scheme[(#, @schemeidfont{quote} #, @schemeidfont{shakey})],
which means the application of the @scheme[shakey] procedure's
argument (which turns out to be a string, not a procedure).
A few other character combinations trigger @litchar{'}-like
conversions, including @litchar{`}, @litchar{,}, @litchar["@,"], and
@litchar{#`}. Also, @litchar{#module big} triggers a read-time
conversion that bundles file content into a single
@scheme[module] declaration (see @secref["module"]).
Normally, @litchar{.} is allowed by the reader only with a
parenthesized sequence, and only before the last element of the
sequence. However, a pair of @litchar{.}s can also appear around a
single element in a parenthesized sequence, as long as the element is
not first or last. Such a pair triggers a reader conversion that
moves the element between @litchar{.}s to the front of the list, which
enables a kind of general infix notation:
@interaction[
(1 . < . 2)
'(1 . < . 2)
]
This two-dot convension is untraditional, and it has essentially
nothing to do with the dot notation for non-list pairs. PLT Scheme
programmers use the infix convension sparingly---mostly for asymmetric
binary operators such as @scheme[<] and @scheme[is-a?].
@;------------------------------------------------------------------------
@section[#:tag "eval-quote"]{Traditional Metaprogramming}
[The whole quote and printer thing has to do with manipulating
programs as represented by pairs, symbols, etc. Not usually a good
idea anymore...]

View File

@ -0,0 +1,208 @@
#reader(lib "docreader.ss" "scribble")
@require[(lib "manual.ss" "scribble")]
@require[(lib "eval.ss" "scribble")]
@require["guide-utils.ss"]
@title[#:tag "intro"]{Welcome to PLT Scheme}
Depending on how you look at it, @bold{PLT Scheme} is
@itemize{
@item{a @defterm{programming language}---a dialect of Scheme, which
is a dialect of Lisp;}
@item{a @defterm{family} of programming languages---variants of
Scheme, and more; or}
@item{a set of @defterm{tools}---for using a family of programming languages.}
}
Where there is no room for confusion, we use simply @defterm{Scheme}
to refer to any of these facets of PLT Scheme.
PLT Scheme's two main tools are
@itemize{
@tool["MzScheme"]{the core compiler, interpreter, and run-time
system; and}
@tool["DrScheme"]{the programming environment (which runs on top of
MzScheme).}
}
Most likely, you'll want to explore PLT Scheme using DrScheme,
especially at the beginning. If you prefer, you can also work with the
command-line @exec{mzscheme} interpreter and your favorite text
editor. The rest of this guide presents the language mostly
independent of the tool that you use.
If you read @Quick and you're still using DrScheme, you already know
about interactions and definitions. You can safely skip to
@secref["indentation"], with the caveat that we call the interactions
window the @defterm{REPL} in this guide.
Otherwise, if you're using DrScheme, you'll need to set it in the
right mode, because DrScheme is less biased to a particular Scheme
variant than @exec{mzscheme}. Assuming that you've never used DrScheme
before, start it up, type the line
@schememod[big]
in DrScheme's top text area, and then click the @onscreen{Run} button
that's above the text area. DrScheme then understands that you mean to
work in the @schememodname[big] variant of Scheme (as opposed to
@schememodname[little], @schememodname[medium], or many other
possibilities).
If you've used DrScheme before with something other than a program
that starts @schemefont{#module}, DrScheme will remember the last language
that you used, instead of inferring the language from the
@schemefont{#module} line. In that case, use the @menuitem["Language"
"Choose Language..."] menu item. In the the dialog that appears,
select the first item, which is @onscreen{Module}. Put the
@schemefont{#module} line above in the top text area, still.
@; ----------------------------------------------------------------------
@section{Interacting with Scheme}
DrScheme's bottom text area and the @exec{mzscheme} command-line
program (when started with no options) both act as a kind of
calculator. You type a Scheme expression, hit return, and the answer
is printed. In the terminology of Scheme, this kind of calculator is
called a @idefterm{read-eval-print loop} or @idefterm{REPL}.
A number by itself is an expression, and the answer is just the
number:
@interaction[5]
A string is also an expression that evaluates to itself. A string is
written with double quotes at the start and end of the string:
@interaction["hello world"]
Scheme uses parentheses to wrap larger expressions---almost any kind
of expression, other than simple constants. For example, a procedure
call is written: open parenthesis, procedure name, argument
expression, and closing parenthesis. The following expression calls
the built-in procedure @scheme[substring] with the arguments
@scheme["hello world"], @scheme[0], and @scheme[5]:
@interaction[(substring "hello world" 0 5)]
@; ----------------------------------------------------------------------
@section{Definitions and Interactions}
You can define your own procedures that work like @scheme[subtring] by
using the @scheme[define] form, like this:
@def+int[
(define (piece str)
(substring str 0 5))
(piece "howdy universe")
]
Although you can evaluate the @scheme[define] form in the REPL,
definitions are normally a part of a program that you want to keep and
use later. So, in DrScheme, you'd normally put the definition in the
top text area---called the @defterm{definitions area}---along with the
@schemefont{#module} prefix:
@schememod[
big
code:blank
(define (piece str)
(substring str 0 5))
]
If calling @scheme[(piece "howdy universe")] is part of the main action
of your program, that would go in the definitions area, too. But if it
was just an example expression that you were using to explore
@scheme[piece], then you'd more likely leave the definitions area as
above, click @onscreen{Run}, and then evaluate
@scheme[(piece "howdy universe")]
in the REPL.
With @exec{mzscheme}, you'd save the above text in a file using your
favorite editor. If you save it as @file{piece.ss}, then after starting
@exec{mzscheme} in the same directory, you'd evaluate the following
sequence:
@interaction[
(eval:alts (enter! "piece.ss") (void))
(piece "howdy universe")
]
The @scheme[enter!] procedure both loads the code and switches the
evaluation context to the inside of the module, just like DrScheme's
@onscreen{Run} button.
@; ----------------------------------------------------------------------
@section{A Note to Readers with Scheme/Lisp Experience}
If you already know something about Scheme or Lisp, you might be
tempted to put just
@schemeblock[
(define (piece str)
(substring str 0 5))
]
into @file{piece.ss} and run @exec{mzscheme} with
@interaction[
(eval:alts (load "piece.ss") (void))
(piece "howdy universe")
]
That will work, because @exec{mzscheme} is willing to imitate a
traditional Scheme environment, but we strongly recommend against using
@scheme[load].
Writing definitions outside of a module leads to bad error messages,
bad performance, and awkward scripting to combine and run
programs. The problems are not in @exec{mzscheme}'s implementation;
they're fundamental limitations of the traditional top-level
environment, which Scheme and Lisp implementations have historically
combated through ad hoc command-line flags, compiler directives, and
build tools. The module system is to designed to avoid the problems,
so start with @schemefont{#module}, and you'll be happier with Scheme
in the long run.
@; ----------------------------------------------------------------------
@section[#:tag "indentation"]{Scheme Program Formatting}
Line breaks and indentation are not significant for parsing Scheme
programs, but most Scheme programmer use a standard set of conventions
to make code more readable. For example, the body of a definition is
typically indented under the first line of the definition. Identifiers
are written immediately after an open parenthesis with no extra space,
and closing parentheses never go on their own line.
DrScheme automatically indents according to the standard style when
you type Enter in a program or REPL expression. For example, if you
hit Enter after typing @litchar{(define (piece str)}, then DrScheme
automatically inserts two spaces for the next line. If you change a
region of code, you can select it in DrScheme and hit Tab, and
DrScheme will re-indent the code (without inserting any line breaks).
Editors like Emacs offer a Scheme mode with similar indentation
support.
Re-indenting not only makes the code easier to read, it gives you
extra feedback that your parentheses are matched in the way that you
intended. For example, if you leave out a closing parenthesis after
the last argument to a procedure, automatic indentation starts the
next line under the first argument, instead of under the
@scheme[define] keyword:
@schemeblock[
(define (piece str
(substring str 0 5)))
]
Furthermore, when an open parenthesis has no matching close
parenthesis in a program, both @exec{mzscheme} and DrScheme use the
source's indentation information to suggest where it might be missing.

View File

@ -0,0 +1,3 @@
(module info (lib "infotab.ss" "setup")
(define name "Scribblings")
(define post-install-collection "doc-installer.ss"))

View File

@ -0,0 +1,11 @@
(module quick mzscheme
(require "to-html.ss"
(prefix quick: "quick/quick.scrbl"))
(provide build)
(define (build)
(to-html #f #f
(list quick:doc)
(list "quick"))))

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,13 @@
(module exn mzscheme
(require (lib "serialize.ss"))
(define-serializable-struct mr-exn (message))
;; Design to print the same as the real canvas:
(define-struct canvas-super ())
(define-serializable-struct (object:canvas% canvas-super) () #f)
(provide (struct mr-exn (message))
make-object:canvas%))

View File

@ -0,0 +1,3 @@
Except for this one, the files in this directory are generated by
building the "quick" document with the environment variable MREVAL
set. Otherwise, the doc build uses the information here.

View File

@ -0,0 +1,105 @@
(0 () 0 () () (c! require c! (c! lib c! "slideshow.ss" c! "slideshow")))
(0 () 0 () () (void))
(0 () 0 () () (c! require-for-syntax c! mzscheme))
(0 () 0 () () (void))
(0 () 0 () () 5)
(0 () 0 () () 5)
(0 () 0 () () "art gallery")
(0 () 0 () () "art gallery")
(0 () 0 () () (c! circle c! 10))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img0.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! rectangle c! 10 c! 20))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img1.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! circle c! 10 c! 20))
(1 ((#"/Users/mflatt/proj/plt/collects/scribblings/quick/exn.ss" . deserialize-info:mr-exn-v0)) 0 () () (0 "procedure circle: expects 1 argument, given 2: 10 20"))
(0 () 0 () () (c! hc-append c! (c! circle c! 10) c! (c! rectangle c! 10 c! 20)))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img2.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! define c! c c! (c! circle c! 10)))
(0 () 0 () () (void))
(0 () 0 () () (c! define c! r c! (c! rectangle c! 10 c! 20)))
(0 () 0 () () (void))
(0 () 0 () () r)
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img3.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! hc-append c! c c! r))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img4.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! hc-append c! 20 c! c c! r c! c))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img5.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! define c! (c! square c! n) c! (c! filled-rectangle c! n c! n)))
(0 () 0 () () (void))
(0 () 0 () () (c! square c! 10))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img6.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! define c! (c! four c! p) c! (c! define c! two-p c! (c! hc-append c! p c! p)) c! (c! vc-append c! two-p c! two-p)))
(0 () 0 () () (void))
(0 () 0 () () (c! four c! (c! circle c! 10)))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img7.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! define c! (c! checker c! p1 c! p2) c! (c! let c! (c! (c! p12 c! (c! hc-append c! p1 c! p2)) c! (c! p21 c! (c! hc-append c! p2 c! p1))) c! (c! vc-append c! p12 c! p21))))
(0 () 0 () () (void))
(0 () 0 () () (c! checker c! (c! colorize c! (c! square c! 10) c! "red") c! (c! colorize c! (c! square c! 10) c! "black")))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img8.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! define c! (c! checkerboard c! p) c! (c! let* c! (c! (c! rp c! (c! colorize c! p c! "red")) c! (c! bp c! (c! colorize c! p c! "black")) c! (c! c c! (c! checker c! rp c! bp)) c! (c! c4 c! (c! four c! c))) c! (c! four c! c4))))
(0 () 0 () () (void))
(0 () 0 () () (c! checkerboard c! (c! square c! 10)))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img9.png" . unix)) (c! "[image]")))))
(0 () 0 () () circle)
(0 () 0 () () (c! define c! (c! series c! mk) c! (c! hc-append c! 4 c! (c! mk c! 5) c! (c! mk c! 10) c! (c! mk c! 20))))
(0 () 0 () () (void))
(0 () 0 () () (c! series c! circle))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img10.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! series c! square))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img11.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! series c! (c! lambda c! (c! size) c! (c! checkerboard c! (c! square c! size)))))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img12.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! define c! (c! rgb-series c! mk) c! (c! vc-append c! (c! series c! (c! lambda c! (c! sz) c! (c! colorize c! (c! mk c! sz) c! "red"))) c! (c! series c! (c! lambda c! (c! sz) c! (c! colorize c! (c! mk c! sz) c! "green"))) c! (c! series c! (c! lambda c! (c! sz) c! (c! colorize c! (c! mk c! sz) c! "blue"))))))
(0 () 0 () () (void))
(0 () 0 () () (c! rgb-series c! circle))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img13.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! rgb-series c! square))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img14.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! define c! (c! rgb-maker c! mk) c! (c! lambda c! (c! sz) c! (c! vc-append c! (c! colorize c! (c! mk c! sz) c! "red") c! (c! colorize c! (c! mk c! sz) c! "green") c! (c! colorize c! (c! mk c! sz) c! "blue")))))
(0 () 0 () () (void))
(0 () 0 () () (c! series c! (c! rgb-maker c! circle)))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img15.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! series c! (c! rgb-maker c! square)))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img16.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! list c! "red" c! "green" c! "blue"))
(0 () 0 () () (c! "red" c! "green" c! "blue"))
(0 () 0 () () (c! list c! (c! circle c! 10) c! (c! square c! 10)))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 1 ("[image]") () (c! (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img17.png" . unix)) (c! (? . 0))))) c! (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img18.png" . unix)) (c! (? . 0)))))))
(0 () 0 () () (c! define c! (c! rainbow c! p) c! (c! map c! (c! lambda c! (c! color) c! (c! colorize c! p c! color)) c! (c! list c! "red" c! "orange" c! "yellow" c! "green" c! "blue" c! "purple"))))
(0 () 0 () () (void))
(0 () 0 () () (c! rainbow c! (c! square c! 5)))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 1 ("[image]") () (c! (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img19.png" . unix)) (c! (? . 0))))) c! (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img20.png" . unix)) (c! (? . 0))))) c! (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img21.png" . unix)) (c! (? . 0))))) c! (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img22.png" . unix)) (c! (? . 0))))) c! (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img23.png" . unix)) (c! (? . 0))))) c! (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img24.png" . unix)) (c! (? . 0)))))))
(0 () 0 () () (c! apply c! vc-append c! (c! rainbow c! (c! square c! 5))))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img25.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! require c! (c! lib c! "flash.ss" c! "texpict")))
(0 () 0 () () (void))
(0 () 0 () () (c! filled-flash c! 40 c! 30))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img26.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! require c! (c! planet c! "random.ss" c! (c! "schematics" c! "random.plt" c! 1 c! 0))))
(0 () 0 () () (void))
(0 () 0 () () (c! random-gaussian))
(0 () 0 () () 0.7386912134436788)
(0 () 0 () () (c! require c! (c! lib c! "code.ss" c! "slideshow")))
(0 () 0 () () (void))
(0 () 0 () () (c! code c! (c! circle c! 10)))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img27.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! define-syntax c! pict+code c! (c! syntax-rules c! () c! (c! (c! pict+code c! expr) c! (c! hc-append c! 10 c! expr c! (c! code c! expr))))))
(0 () 0 () () (void))
(0 () 0 () () (c! pict+code c! (c! circle c! 10)))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img28.png" . unix)) (c! "[image]")))))
(0 () 0 () () (c! require c! (c! lib c! "class.ss" c! "mzlib") c! (c! lib c! "mred.ss" c! "mred")))
(0 () 0 () () (void))
(0 () 0 () () (c! define c! f c! (c! new c! frame% c! (c! label c! "My Art") c! (c! width c! 300) c! (c! height c! 300) c! (c! alignment c! (c! quote c! (c! center c! center))))))
(0 () 0 () () (void))
(0 () 0 () () (c! send c! f c! show c! #t))
(0 () 0 () () (void))
(0 () 0 () () (c! send c! f c! show c! #f))
(0 () 0 () () (void))
(0 () 0 () () (c! define c! (c! add-drawing c! p) c! (c! let c! (c! (c! drawer c! (c! make-pict-drawer c! p))) c! (c! new c! canvas% c! (c! parent c! f) c! (c! style c! (c! quote c! (c! border))) c! (c! paint-callback c! (c! lambda c! (c! self c! dc) c! (c! drawer c! dc c! 0 c! 0)))))))
(0 () 0 () () (void))
(0 () 0 () () (c! add-drawing c! (c! pict+code c! (c! circle c! 10))))
(1 ((#"/Users/mflatt/proj/plt/collects/scribblings/quick/exn.ss" . deserialize-info:object:canvas%-v0)) 0 () () (0))
(0 () 0 () () (c! add-drawing c! (c! colorize c! (c! filled-flash c! 50 c! 30) c! "yellow")))
(1 ((#"/Users/mflatt/proj/plt/collects/scribblings/quick/exn.ss" . deserialize-info:object:canvas%-v0)) 0 () () (0))
(0 () 0 () () (c! scale c! (c! bitmap c! "quick/art.png") c! 0.5))
(2 (((lib "struct.ss" "scribble") . deserialize-info:element-v0) ((lib "struct.ss" "scribble") . deserialize-info:image-file-v0)) 0 () () (0 #f (c! (0 (1 (p+ #"/Users/mflatt/proj/plt/collects/scribblings/quick/images/img29.png" . unix)) (c! "[image]")))))

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 710 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 718 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 837 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

View File

@ -0,0 +1,138 @@
(module mreval mzscheme
(require (lib "eval.ss" "scribble")
(lib "struct.ss" "scribble")
(lib "config.ss" "scribble")
(lib "scheme.ss" "scribble")
(lib "class.ss")
(lib "file.ss")
(lib "runtime-path.ss")
(lib "serialize.ss")
"exn.ss")
(define-syntax define-mr
(syntax-rules ()
[(_ mr orig)
(begin
(provide mr)
(define-syntax mr
(syntax-rules ()
[(_ x (... ...))
(parameterize ([scribble-eval-handler mr-eval-handler]
[current-int-namespace mr-namespace])
(orig x (... ...)))])))]))
(define-mr mr-interaction interaction)
(define-mr mr-interaction-eval interaction-eval)
(define-mr mr-interaction-eval-show interaction-eval-show)
(define-mr mr-def+int def+int)
(define-mr mr-defs+int defs+int)
(define-mr mr-schememod+eval schememod+eval)
(define-mr mr-schemeblock+eval schemeblock+eval)
(define mred? (getenv "MREVAL"))
(define-runtime-path img-dir "images")
(define-runtime-path exn-module "exn.ss")
(define mr-eval-handler
(if mred?
(let ([eh (scribble-eval-handler)]
[log-file (open-output-file (build-path img-dir "exprs.dat") 'truncate/replace)])
(lambda (catching-exns? expr)
(write (serialize expr) log-file)
(newline log-file)
(flush-output log-file)
(let ([result
(with-handlers ([exn:fail?
(lambda (exn)
(make-mr-exn (exn-message exn)))])
(eh catching-exns? expr))])
(let ([result (fixup-picts result)])
(write (serialize result) log-file)
(newline log-file)
(flush-output log-file)
(if (mr-exn? result)
(raise (make-exn:fail
(mr-exn-message result)
(current-continuation-marks)))
result)))))
(let ([log-file (with-handlers ([exn:fail:filesystem?
(lambda (exn)
(open-input-string ""))])
(open-input-file (build-path img-dir "exprs.dat")))])
(lambda (catching-exns? expr)
(with-handlers ([exn:fail? (lambda (exn)
(if catching-exns?
(raise exn)
(void)))])
(let ([v (read log-file)])
(if (eof-object? v)
(error "expression not in log file")
(let ([v (deserialize v)])
(if (equal? v expr)
(let ([v (read log-file)])
(if (eof-object? v)
(error "expression result missing in log file")
(let ([v (deserialize v)])
(if (mr-exn? v)
(raise (make-exn:fail
(mr-exn-message v)
(current-continuation-marks)))
v))))
(error 'mreval
"expression does not match log file: ~e versus: ~e"
expr
v))))))))))
(define mr-namespace
(if mred?
(current-int-namespace ((dynamic-require '(lib "mred.ss" "mred") 'make-namespace-with-mred)))
(let ([ns (make-namespace)])
(namespace-attach-module (current-namespace)
'(lib "struct.ss" "scribble")
ns)
(namespace-attach-module (current-namespace)
exn-module
ns)
ns)))
(define image-counter 0)
(define (ss:pict?)
(with-handlers ([exn:fail? (lambda (x) (lambda (x) #f))])
(eval 'pict? mr-namespace)))
(define (ss:pict-width)
(eval 'pict-width mr-namespace))
(define (ss:pict-height)
(eval 'pict-height mr-namespace))
(define (ss:make-pict-drawer)
(eval 'make-pict-drawer mr-namespace))
(define (ss:colorize)
(eval 'colorize mr-namespace))
(define (mred:canvas%)
(dynamic-require '(lib "mred.ss" "mred") 'canvas%))
(define (mred:bitmap%)
(dynamic-require '(lib "mred.ss" "mred") 'bitmap%))
(define (mred:bitmap-dc%)
(dynamic-require '(lib "mred.ss" "mred") 'bitmap-dc%))
(define (fixup-picts v)
(cond
[((ss:pict?) v)
(let ([fn (build-path img-dir (format "img~a.png" image-counter))])
(set! image-counter (add1 image-counter))
(let* ([bm (make-object (mred:bitmap%)
(inexact->exact (ceiling ((ss:pict-width) v)))
(inexact->exact (ceiling ((ss:pict-height) v))))]
[dc (make-object (mred:bitmap-dc%) bm)])
(send dc set-smoothing 'aligned)
(send dc clear)
(((ss:make-pict-drawer) ((ss:colorize) v value-color)) dc 0 0)
(send bm save-file fn 'png)
(make-element #f (list (make-element (make-image-file fn) (list "[image]"))))))]
[(is-a? v (mred:canvas%))
(make-object:canvas%)]
[(pair? v) (cons (fixup-picts (car v))
(fixup-picts (cdr v)))]
[else v])))

View File

@ -0,0 +1,561 @@
#reader(lib "docreader.ss" "scribble")
@title{An Introduction to PLT Scheme with Pictures}
@; ----------------------------------------------------------------------
@require[(lib "manual.ss" "scribble")]
@require["mreval.ss"]
@require[(lib "urls.ss" "scribble")]
@mr-interaction-eval[(require (lib "slideshow.ss" "slideshow"))]
@mr-interaction-eval[(require-for-syntax mzscheme)]
@; ----------------------------------------------------------------------
@section{Why Pictures? Why DrScheme?}
This tutorial provides a brief introduction to the PLT Scheme
programming language by using one of its picture-drawing
libraries. Even if you don't intend to use Scheme for your artistic
endeavours, the picture library supports interesting and enlightening
examples. After all, a picture is worth five hundred ``hello world''s.
Along the same lines, we assume that you will run the examples using
@link[url:download-drscheme]{DrScheme}. Using DrScheme is the fastest
way to get a sense of what the language and system feels like, even if
you eventually use Scheme with Emacs, vi, or some other editor.
@; ----------------------------------------------------------------------
@section{Ready...}
@link[url:download-drscheme]{Download PLT Scheme}, install, and then
start DrScheme.
@; ----------------------------------------------------------------------
@section{Set...}
To draw pictures, we must first load the picture library. Copy the
following into the @defterm{definitions area}, which is the top text
area that you see in DrScheme:
@schememod[slideshow]
Then click the @onscreen{Run} button. You'll see the text caret move
to the bottom text area, which is the @defterm{interactions area}.
If you've used DrScheme before, you might need to manually reset the
language to @onscreen{Module} via the @menuitem["Language" "Choose
Language..."] menu item before clicking @onscreen{Run}.
@; ----------------------------------------------------------------------
@section{Go!}
When you type an expression after the @onscreen{>} in the interactions
window and hit Enter, DrScheme evaluates the expression and prints its result. An
expression can be just a value, such as the number @scheme[5] or the
string @scheme["art gallery"]:
@mr-interaction[5 "art gallery"]
An expression can also be a procedure call. To call a procedure, put
an open parenthesis before the procedure name, then expressions for the
procedure arguments, and then a close parenthesis, like this:
@mr-interaction[(circle 10)]
A result from the @scheme[circle] procedure is a picture value, which
prints as an expression result in much the same way that numbers or
strings print. The argument to @scheme[circle] determines the
circle's size in pixels. As you might guess, there's a
@scheme[rectangle] procedure that takes two arguments instead of one:
@mr-interaction[(rectangle 10 20)]
Try giving @scheme[circle] the wrong number of arguments, just to see
what happens:
@mr-interaction[(circle 10 20)]
Note that DrScheme highlights the source of the error in pink.
In addition to basic picture constructors like @scheme[circle] and
@scheme[rectangle], there's a @scheme[hc-append] procedure that
combines pictures. When you start composing procedure calls in Scheme,
it looks like this:
@mr-interaction[(hc-append (circle 10) (rectangle 10 20))]
The hyphen in the name @scheme[hc-append] is just a part of the
identifier; it's not @scheme[hc] minus @scheme[append]. The procedure
name starts with @scheme[h] because it combines pictures horizontally,
and the next letter is @scheme[c] because the pictures are centered
vertically. If you wonder what other functions exist (perhaps a way to
stack pictures vertically and left-aligned), move the text caret to
the name @scheme[hc-append] and press the F1 key in DrScheme. A Help
Desk window will appear, and it will give you a link to the
documentation for @scheme[hc-append]. Click the link, and you'll see
lots of other functions.
@; ----------------------------------------------------------------------
@section{Definitions}
To use a particular circle and rectangle picture many times, it's
simpler to give them names. Move back to the definitions area (the top
area) and add two definitions, so that the complete content of the
definitions area looks like this:
@mr-schememod+eval[
slideshow
(define c (circle 10))
(define r (rectangle 10 20))
]
Then click @onscreen{Run} again. Now, you can just type @scheme[c] or
@scheme[r]:
@mr-interaction[r (hc-append c r) (hc-append 20 c r c)]
As you can see, the @scheme[hc-append] function accepts an optional
number argument before the picture arguments, and it accepts any
number of picture arguments. When a number is provided, it specifies
the amount of space to add between pictures.
We could have evaluated the @scheme[define] forms for @scheme[c] and
@scheme[r] in the interactions area instead of the interactions
area. In practice, though, the definitions area is where your program
lives---it's the file that you save---while the interaction area is
for transient explorations and debugging tasks.
Let's add a procedure definition to the program. A procedure
definition uses @scheme[define], just like our shape definitions, but with
an open parenthesis before the procedure name, and names for the
procedure arguments before the matching close parenthesis:
@mr-schemeblock+eval[
(define (square n)
(code:comment #, @t{A semi-colon starts a line comment.})
(code:comment #, @t{The expresson below is the function body.})
(filled-rectangle n n))
]
The syntax of the definition mirrors the syntax of a procedure
call:
@mr-interaction[(square 10)]
In the same way that definitions can be evaluated in the interactions
area, expressions can be included in the definitions area. When a
program is run, expression results from the definition area are shown
in the interaction area. From now on, we'll write our example
definitions and expressions together, and you can put them in
whichever area you prefer. The examples will build on each other,
however, so it's best to put at least the definitions in the
definition area.
@; ----------------------------------------------------------------------
@section{Local Binding}
The @scheme[define] form can be used in some places to create local
bindings. For example, it can be used inside a procedure body:
@mr-def+int[
(define (four p)
(define two-p (hc-append p p))
(vc-append two-p two-p))
(four (circle 10))
]
More typically, Schemers use the @scheme[let] or @scheme[let*] form
for local binding. An advantage of @scheme[let] is that it can be used
in any expression position. Also, it binds many identifiers at once,
instead of requiring a separate @scheme[define] for each identifier:
@mr-def+int[
(define (checker p1 p2)
(let ([p12 (hc-append p1 p2)]
[p21 (hc-append p2 p1)])
(vc-append p12 p21)))
(checker (colorize (square 10) "red")
(colorize (square 10) "black"))
]
A @scheme[let] form binds many identifiers at the same time, so the
bindings cannot refer to each other. The @scheme[let*] form, in
contrast, allows later bindings to use earlier bindings:
@mr-def+int[
(define (checkerboard p)
(let* ([rp (colorize p "red")]
[bp (colorize p "black")]
[c (checker rp bp)]
[c4 (four c)])
(four c4)))
(checkerboard (square 10))
]
@; ----------------------------------------------------------------------
@section{Procedures are Values}
Instead of calling @scheme[circle] as a procedure, try evaluating just
@scheme[circle] as an expression:
@mr-interaction[circle]
That is, the identifier @scheme[circle] is bound to a procedure, just
like @scheme[c] is bound to a circle. Unlike a cicrle picture, there's
not a simple way of completely printing the procedure, so DrScheme just
prints @procedure{circle}.
This example shows that procedures are values, just like numbers and
pictures (even if they don't print as nicely). Since procedures are
values, you can define procedures that expect other procedures as
arguments:
@mr-def+int[
(define (series mk)
(hc-append 4 (mk 5) (mk 10) (mk 20)))
(series circle)
(series square)
]
When calling a procedure that accepts a procedure argument, the
argument procedure often isn't needed anywhere else. Having to write
down the function via @scheme[define] would be a hassle, because you
have to make up a name and find a place to put the procedure
definition. The alternative is to use @scheme[lambda], which creates an
anonymous procedure:
@mr-interaction[(series (lambda (size) (checkerboard (square size))))]
The parenthesized name(s) after a @scheme[lambda] are the argument to
the procedure, and the expression after the argument names is the
procedure body. Using the word ``lambda'' instead of ``function'' or
``procedure'' is part of Scheme's history and culture.
A procedure-form @scheme[define] is really a shorthand for a simple
@scheme[define] using @scheme[lambda] as the value. For example, the
@scheme[series] definition could be written as
@schemeblock[
(define series
(lambda (mk)
(hc-append 4 (mk 5) (mk 10) (mk 20))))
]
Most Schemers prefer to use the shorthand procedure form with
@scheme[define] instead of expanding to @scheme[lambda], but
@scheme[lambda] shows up often with @scheme[letrec] to define mutually
recursive procedures; see @link["elsewhere"]{elsewhere} for
examples.
@; ----------------------------------------------------------------------
@section{Lexical Scope}
Scheme is a lexically scoped language, which means that whenever an
identifier is used as an expression, something in the textual
environment of the expression determines the identifier's
binding. This rule applies to identifiers in a @scheme[lambda] body as
well as anywhere else.
For example, in the following @scheme[color-series] procedure the uses
of @scheme[mk] in each @scheme[lambda] form refer to the argument of
@scheme[color-series], since that's the binding that textually in
scope:
@mr-def+int[
(define (rgb-series mk)
(vc-append
(series (lambda (sz) (colorize (mk sz) "red")))
(series (lambda (sz) (colorize (mk sz) "green")))
(series (lambda (sz) (colorize (mk sz) "blue")))))
(rgb-series circle)
(rgb-series square)
]
Here's another example, where @scheme[rgb-maker] takes a procedure and
returns a new one that remembers and uses the original procedure.
@mr-def+int[
(define (rgb-maker mk)
(lambda (sz)
(vc-append (colorize (mk sz) "red")
(colorize (mk sz) "green")
(colorize (mk sz) "blue"))))
(series (rgb-maker circle))
(series (rgb-maker square))
]
Note how composing procedures via @scheme[rgb-maker] creates a
different alignment of objects within the picture compared to using
@scheme[rgb-series].
@; ----------------------------------------------------------------------
@section{Lists}
Scheme inherits much of its style from the langauge Lisp, whose name
originally stood for ``LISt Processor,'' and lists remain an important
part of Scheme.
The @scheme[list] procedure takes any number of arguments and returns
a list containing the given values:
@mr-interaction[(list "red" "green" "blue")
(list (circle 10) (square 10))]
As you can see, a list prints as a pair of parentheses wrapped around
the printed form of the list elements. There's room for confusion
here, because parentheses are used for both expressions, such as
@scheme[(circle 10)], and printed results, such as
@schemeresult[("red" "green" "blue")]. This connection between
expressions and printed results is no coincidence, but we save that
bit of culture for @link["elsewhere"]{discussion elsewhere}.
If you have a list, then you'll eventually want to do something with
each of the elements. The @scheme[map] procedure takes a list and a
procedure to apply to each element of the list; it returns a new list
to report the procedure's results:
@mr-def+int[
(define (rainbow p)
(map (lambda (color)
(colorize p color))
(list "red" "orange" "yellow" "green" "blue" "purple")))
(rainbow (square 5))
]
Another procedure that works with lists is @scheme[apply]. Like
@scheme[map], it takes a procedure and a list, but a procedure given
to @scheme[apply] should take all of the arguments at once, instead of
each one individually. The @scheme[apply] function is especially
useful with functions that take any number of arguments, such as
@scheme[vc-append]:
@mr-interaction[
(apply vc-append (rainbow (square 5)))
]
Note that @scheme[(vc-append (rainbow (square 5)))] would not work,
because @scheme[vc-append] does not want a list as an argument; it
wants a picture as an argument, and it is willing to accept any number
of them. The @scheme[apply] procedure bridges the gap between a
procedure that wants many arguments and a list of those arguments as a
single value.
@; ----------------------------------------------------------------------
@section{Modules}
Since your program in the definitions window starts with
@schememod[slideshow]
all of the code that you put in the definitions window is inside a
module. Furthermore, the module intially imports everything from the
module designated by @schememodname[slideshow], which exports
picture-making procedures as well as more commonly used procedures
such as @scheme[list] and @scheme[map].
To import additional libraries, use the @scheme[require] form. For
example, the library @scheme[(lib "flash.ss" "texpict")] provides a
@scheme[filled-flash] procedure:
@mr-def+int[
(require (lib "flash.ss" "texpict"))
(filled-flash 40 30)
]
Modules are named and distributed in various ways:
@itemize[
@item{Some modules are packaged in the PLT Scheme distribution or
otherwise installed into a hierarchy of
@defterm{collections}. For example, the module name
@schememodname[(lib "flash.ss" "texpict")] means ``the module
implemented in the file @file{flash.ss} that is located in the
@file{texpict} collection.'' The @schememodname[slideshow]
specification with @schemefont{#module} is a shorthand for
@schememodname[(lib "lang.ss" "slideshow")].}
@item{Some modules are distributed through the
@link[url:planet]{@PLaneT} server, and they can be
downloaded automatically on demand. For example, the first time
that you evaluate the following fragment:
@mr-def+int[
(require (planet "random.ss" ("schematics" "random.plt" 1 0)))
(random-gaussian)
]
DrScheme automatically downloads version 1.0 of the
@file{random.plt} library and then imports the
@file{random.ss} module.}
@item{Some modules live relative to other modules, without
necessarily belonging to any particular collection or package.
For example, in DrScheme, if save your definitions so far in a
file @file{quick.ss} and add the line
@schemeblock[(provide rainbow square)]
then you can open a new tab or window in DrScheme, type the new
program @file{use.ss} in the same directory as @file{quick.ss}:
@schememod[
little
(require "quick.ss")
(rainbow square)
]
and when you run this later program, a rainbow list of squares
is the output. Note that @file{use.ss} is written using the
initial import @schememodname[little], which does not
supply any picture-making procedures itself---but does provide
@scheme[require] and the procedure-calling syntax.}
]
Schemers typically write new programs and libraries as modules that
import each other through relative paths, and that use existing
libraries via @scheme[lib] and @scheme[planet]. When a program or
library developed this way seems useful to others, it can be uploaded
as a @PLaneT package or distributed in the more old-fashioned way as
an installable collection archive (in either case without modifying
the internal relative references among modules).
@; ----------------------------------------------------------------------
@section{Macros}
Here's another library to try:
@mr-def+int[
(require (lib "code.ss" "slideshow"))
(code (circle 10))
]
Instead of a circle, the result is a picture of the code that, if it
were used as an expression, would produce a circle. In other words,
@scheme[code] is not a procedure, but instead a new syntactic form for
creating pictures; the bit between the opening parenthesese with
@scheme[code] is not an expression, but instead manipulated by the
@scheme[code] syntactic form.
This helps explain what we meant in the previous section when we said
that @schememodname[little] provides @scheme[require] and the
procedure-calling syntax. Libraries are not restricted to exporting
values, such as procedures; they can also define new syntax. In this
sense, Scheme isn't exactly language at all; it's more of an idea for
how to structure a language to that you can extend it or create
entirely new languages.
One way to introduce a new syntactic form is through
@scheme[define-syntax] with @scheme[syntax-rules]:
@mr-def+int[
(define-syntax pict+code
(syntax-rules ()
[(pict+code expr)
(hc-append 10
expr
(code expr))]))
(pict+code (circle 10))
]
This kind of definition is a macro. The @scheme[(pict+code expr)] part
is a pattern for uses of the macro; instances of the pattern in a
program are replaced by instances of the corresponding template, which
is @scheme[(hc-append 10 expr (code expr))]. In particular,
@scheme[(pict+code (circle 10))] matches the pattern with
@scheme[(circle 10)] as @scheme[expr], so it is replaced with
@scheme[(hc-append 10 (circle 10) (code (circle 10)))].
Of course, the sword of syntactic extension cuts both ways: inventing
a new language can make it easer to say what you want, but harder for
others to understand. As it happens, the developers of Scheme are
constantly giving talks and writing papers that involve Scheme code,
and it's worthwhile for everyone who works on those products to know
about @scheme[code].
In fact, you might want to take a look at the @link["quick/quick.scrbl"]{source of
this document}. You'll see that it starts with @schemefont{#module},
but otherwise doesn't look a lot like Scheme; nevertheless, we build
this document by running its source as a PlT Scheme program. We have
to use a lot more than @scheme[syntax-rules] to extend Scheme's syntax
enough for writing documents, but Scheme's syntactic extension can
take you a long way!
@; ----------------------------------------------------------------------
@section{Objects}
An object system is another example of a sophisticated language
extension that is worth learning and using for a Scheme users. Objects
are sometimes better than procedures, even when you have
@scheme[lambda], and objects work especially well for graphical user
interfaces. The API for Scheme's GUI and graphics system is expressed
in terms of objects and classes.
The class system itself is implemented by the @schememodname[(lib
"class.ss" "mzlib")] library, and the @schememodname[(lib "mred.ss"
"mred")] library provides the GUI and drawing classes. By convention,
the MrEd classes are given names that end with @scheme[%]:
@mr-defs+int[
[(require (lib "class.ss" "mzlib")
(lib "mred.ss" "mred"))
(define f (new frame% [label "My Art"]
[width 300]
[height 300]
[alignment '(center center)]))]
(send f show #t)
]
@mr-interaction-eval[(send f show #f)]
The @scheme[new] form creates an instances of a class, where
initialization arguments like @scheme[label] and @scheme[width] are
provided by name. The @scheme[send] form calls a method of the object,
such as @scheme[show], with arguments after the method name; the
argument @scheme[#t] in this case is the boolean constant ``true.''
Pictures generated with @schememodname[slideshow] encapsulate a
function that uses MrEd's drawing commands to render the picture to a
drawing context, such as a canvas in a frame. The
@scheme[make-pict-drawer] procedure from @schememodname[slideshow]
exposes a picture's drawing procedure. We can use
@scheme[make-pict-drawer] in a canvas-painting callback to draw a
picture into a canvas:
@mr-def+int[
(define (add-drawing p)
(let ([drawer (make-pict-drawer p)])
(new canvas% [parent f]
[style '(border)]
[paint-callback (lambda (self dc)
(drawer dc 0 0))])))
(add-drawing (pict+code (circle 10)))
(add-drawing (colorize (filled-flash 50 30) "yellow"))
]
@centerline{@mr-interaction-eval-show[(scale (bitmap "quick/art.png") 0.5)]}
Each canvas stratches to fill an equal portion of the frame, because
that's how a frame manages its children by default.
@; ----------------------------------------------------------------------
@section{Where to Go From Here}
This introduction to PLT Scheme purposely avoids many of the
traditional ways of introducing and distinguishing Lisp or Scheme:
prefix arithmetic notation, symbols, quoting and quasiquoting lists,
@scheme[eval], first-class continuations, and the idea that all syntax
is really just a @scheme[lambda] in disguise. While those are all part
of PLT Scheme, they are not the main ingredients of day-to-day programming
in PLT Scheme.
Instead, PLT Scheme programmers typically program with procedures,
records, objects, exceptions, regular expressions, modules, and
threads. That is, instead of a ``minimalist'' language---which is the
way that Scheme is often described---PLT Scheme offers a rich language
with an extensive set of libraries and tools.
To start learning about the full PLT Scheme language and tools in
depth, move on to @link["../guide/index.html"]{A Guide to PLT Scheme}.

View File

@ -0,0 +1,327 @@
#reader(lib "docreader.ss" "scribble")
@require["mz.ss"]
@title[#:tag "bytestrings"]{Byte Strings}
A @pidefterm{byte string} is a fixed-length arary of bytes. A
@pidefterm{byte} is an exact integer between @scheme[0] and
@scheme[255] inclusive.
@index['("byte strings" "immutable")]{A} byte string can be
@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.
Two byte strings are @scheme[eq?] when mutating one would mutate the
other. Two byte strings are @scheme[eqv?] and @scheme[equal?] when
they have the same length and contain the same sequence of bytes.
See also: @scheme[immutable].
@; ----------------------------------------
@section{Byte String Constructors, Selectors, and Mutators}
@defproc[(make-bytes [k exact-nonnegative-integer?] [b byte? 0])
bytes?]{ Returns a new mutable byte string of length @scheme[k] where each
position in the byte string is initialized with the byte @scheme[b].
@examples[(make-bytes 5 65)]}
@defproc[(bytes [b byte?] ...0) bytes?]{ Returns a new mutable byte
string whose length is the number of provided @scheme[b]s, and whose
positions are initialized with the given @scheme[b]s.
@examples[(bytes 65 112 112 108 101)]}
@defproc[(bytes->immutable-bytes [bstr bytes?]) (and/c bytes?
immutable?)]{ Returns an immutable byte string with the same content
as @scheme[bstr], returning @scheme[bstr] itself if @scheme[bstr] is
immutable.}
@defproc[(bytes? [v any/c]) boolean?]{ Returns @scheme[#t] if @scheme[v]
is a byte string, @scheme[#f] otherwise.
@examples[(bytes? #"Apple") (bytes? "Apple")]}
@defproc[(byte? [v any/c]) boolean?]{ Returns @scheme[#t] if @scheme[v] is
a byte (i.e., an exact integer between @scheme[0] and @scheme[255]
inclusive), @scheme[#f] otherwise.
@examples[(byte? 65) (byte? 0) (byte? 256) (byte? -1)]}
@defproc[(bytes-length [bstr bytes?]) exact-nonnegative-integer?]{
Returns the length of @scheme[bstr].
@examples[(bytes-length #"Apple")]}
@defproc[(bytes-ref [bstr bytes?] [k exact-nonnegative-integer?])
byte?]{ Returns the character at position @scheme[k] in @scheme[bstr].
The first position in the bytes cooresponds to @scheme[0], so the
position @scheme[k] must be less than the length of the bytes,
otherwise the @exnraise[exn:fail:contract].
@examples[(bytes-ref #"Apple" 0)]}
@defproc[(bytes-set! [bstr (and/c bytes? (not/c immutable?))] [k
exact-nonnegative-integer?] [b byte?]) void?]{ Changes the
character position @scheme[k] in @scheme[bstr] to @scheme[b]. The first
position in the byte string cooresponds to @scheme[0], so the position
@scheme[k] must be less than the length of the bytes, otherwise the
@exnraise[exn:fail:contract].
@examples[(define s (bytes 65 112 112 108 101))
(bytes-set! s 4 121)
s]}
@defproc[(subbytes [bstr bytes?] [start exact-nonnegative-integer?]
[end exact-nonnegative-integer? (bytes-length str)]) bytes?]{
Returns a new mutable byte string that is @scheme[(- @scheme[end]
@scheme[start])] bytes long, and that contains the same bytes
as @scheme[bstr] from @scheme[start] inclusive to @scheme[end] exclusive. The
@scheme[start] and @scheme[end] arguments must be less than the length of
@scheme[bstr], and @scheme[end] must be greater than or equal to @scheme[bstr],
otherwise the @exnraise[exn:fail:contract].
@examples[(subbytes #"Apple" 1 3)
(subbytes #"Apple" 1)]}
@defproc[(bytes-copy [bstr bytes?]) bytes?]{ Returns
@scheme[(subbytes str 0)].}
@defproc[(bytes-copy! [dest (and/c bytes? (not/c immutable?))]
[dest-start exact-nonnegative-integer?]
[src bytes?]
[src-start exact-nonnegative-integer? 0]
[src-end exact-nonnegative-integer? (bytes-length src)])
void?]{
Changes the bytes of @scheme[dest] from positions
@scheme[dest-start] (inclusive) to @scheme[dest-end] (exclusive) to
match the bytes in @scheme[src] from @scheme[src-start]
(inclusive). The bytes strings @scheme[dest] and @scheme[src] can be the
same byte string, and in that case the destination region can overlap with
the source region; the destination bytes after the copy match
the source bytes from before the copy. If any of
@scheme[dest-start], @scheme[src-start], or @scheme[src-end]
are out of range (taking into account the sizes of the bytes strings and
the source and destination regions), the
@exnraise[exn:fail:contract].
@examples[(define s (bytes 65 112 112 108 101))
(bytes-copy! s 4 #"y")
(bytes-copy! s 0 s 3 4)
s]}
@defproc[(bytes-fill! [dest (and/c bytes? (not/c immutable?))] [char
char?]) void?]{ Changes @scheme[dest] so that every position in the
bytes is filled with @scheme[char].
@examples[(define s (bytes 65 112 112 108 101))
(bytes-fill! s 113)
s]}
@defproc[(bytes-append [bstr bytes?] ...0) bytes?]{ Returns a new
mutable byte string that is as long as the sum of the given @scheme[bstr]s'
lengths, and that contains the concatenated bytes of the given
@scheme[bstr]s. If no @scheme[bstr]s are provided, the result is a zero-length
byte string.
@examples[(bytes-append #"Apple" #"Banana")]}
@defproc[(bytes->list [bstr bytes?]) (listof byte?)]{ Returns a new
list of bytes coresponding to the content of @scheme[bstr]. That is,
the length of the list is @scheme[(bytes-length @scheme[bstr])], and the
sequence of bytes of @scheme[bstr] are in the same sequence in the
result list.
@examples[(bytes->list #"Apple")]}
@defproc[(list->bytes [lst (listof byte?)]) bytes?]{ Returns a new
mutable bytes whose content is the list of bytes in @scheme[lst].
That is, the length of the bytes is @scheme[(length @scheme[lst])], and
the sequence of bytes in @scheme[lst] is in the same sequence in
the result bytes.
@examples[(list->bytes (list 65 112 112 108 101))]}
@; ----------------------------------------
@section{Byte String Comparisons}
@defproc[(bytes=? [bstr1 bytes?] [bstr2 bytes?] ...1) boolean?]{ Returns
@scheme[#t] if all of the arguments are @scheme[eqv?].}
@examples[(bytes=? #"Apple" #"apple")
(bytes=? #"a" #"as" #"a")]
@define[(bytes-sort direction)
@elem{Like @scheme[bytes<?], but checks whether the arguments are @|direction|.}]
@defproc[(bytes<? [bstr1 bytes?] [bstr2 bytes?] ...1) boolean?]{
Returns @scheme[#t] if the arguments are lexicographically sorted
increasing, where individual bytes are ordered by @scheme[<],
@scheme[#f] otherwise.
@examples[(bytes<? #"Apple" #"apple")
(bytes<? #"apple" #"Apple")
(bytes<? #"a" #"b" #"c")]}
@defproc[(bytes>? [bstr1 bytes?] [bstr2 bytes?] ...1) boolean?]{
@bytes-sort["decreasing"]
@examples[(bytes>? #"Apple" #"apple")
(bytes>? #"apple" #"Apple")
(bytes>? #"c" #"b" #"a")]}
@; ----------------------------------------
@section{Bytes to/from Characters, Decoding and Encoding}
@defproc[(bytes->string/utf-8 [bstr bytes?]
[err-char (or/c false/c char?) #f]
[start exact-nonnegative-integer? 0]
[end exact-nonnegative-integer? (bytes-length bstr)])
string?]{
Produces a string by decoding the @scheme[start] to @scheme[end]
substring of @scheme[bstr] as a UTF-8 encoding of Unicode code points.
If @scheme[err-char] is not @scheme[#f], then it is used
for bytes that fall in the range @scheme[#o200] to @scheme[#o377] but
are not part of a valid encoding sequence. (This is consistent with
reading characters from a port; see @secref["ports"] for more details.)
If @scheme[err-char] is @scheme[#f], and if the
@scheme[start] to @scheme[end] substring of @scheme[bstr] is not a valid
UTF-8 encoding overall, then the @exnraise[exn:fail:contract].}
@defproc[(bytes->string/locale [bstr bytes?]
[err-char (or/c false/c char?) #f]
[start exact-nonnegative-integer? 0]
[end exact-nonnegative-integer? (bytes-length bstr)])
string?]{
Produces a string by decoding the @scheme[start] to @scheme[end] substring
of @scheme[bstr] using the current locale's encoding (see also
@secref["locales"]). If @scheme[err-char] is not
@scheme[#f], it is used for each byte in @scheme[bstr] that is not part
of a valid encoding; if @scheme[err-char] is @scheme[#f], and if the
@scheme[start] to @scheme[end] substring of @scheme[bstr] is not a valid
encoding overall, then the @exnraise[exn:fail:contract].}
@defproc[(bytes->string/latin-1 [bstr bytes?]
[err-char (or/c false/c char?) #f]
[start exact-nonnegative-integer? 0]
[end exact-nonnegative-integer? (bytes-length bstr)])
string?]{
Produces a string by decoding the @scheme[start] to @scheme[end] substring
of @scheme[bstr] as a Latin-1 encoding of Unicode code points; i.e.,
each byte is translated directly to a character using
@scheme[integer->char], so the decoding always succeeds. (See also the
Latin-1 footnote of @secref["encodings"].) The @scheme[err-char]
argument is ignored, but present for consistency with the other
operations.}
@defproc[(string->bytes/utf-8 [str string?]
[err-byte (or/c false/c byte?) #f]
[start exact-nonnegative-integer? 0]
[end exact-nonnegative-integer? (string-length str)])
bytes?]{
Produces a byte string by encoding the @scheme[start] to @scheme[end]
substring of @scheme[str] via UTF-8 (always succeeding). The
@scheme[err-byte] argument is ignored, but included for consistency with
the other operations.}
@defproc[(string->bytes/locale [str string?]
[err-byte (or/c false/c byte?) #f]
[start exact-nonnegative-integer? 0]
[end exact-nonnegative-integer? (string-length str)])
bytes?]{
Produces a string by encoding the @scheme[start] to @scheme[end] substring
of @scheme[str] using the current locale's encoding (see also
@secref["locales"]). If @scheme[err-byte] is not @scheme[#f], it is used
for each character in @scheme[str] that cannot be encoded for the
current locale; if @scheme[err-byte] is @scheme[#f], and if the
@scheme[start] to @scheme[end] substring of @scheme[str] cannot be encoded,
then the @exnraise[exn:fail:contract].}
@defproc[(string->bytes/latin-1 [str string?]
[err-byte (or/c false/c byte?) #f]
[start exact-nonnegative-integer? 0]
[end exact-nonnegative-integer? (string-length str)])
bytes?]{
Produces a string by encoding the @scheme[start] to @scheme[end] substring
of @scheme[str] using Latin-1; i.e., each character is translated
directly to a byte using @scheme[char->integer]. If @scheme[err-byte] is
not @scheme[#f], it is used for each character in @scheme[str] whose
value is greater than @scheme[255]. (See also the Latin-1 footnote of
@secref["encodings"]. If @scheme[err-byte] is @scheme[#f], and if the
@scheme[start] to @scheme[end] substring of @scheme[str] has a character
with a value greater than @scheme[255], then the
@exnraise[exn:fail:contract].}
@defproc[(string-utf-8-length [str string?]
[start exact-nonnegative-integer? 0]
[end exact-nonnegative-integer? (string-lenght str)])
exact-nonnegative-integer?]{
Returns the length in bytes of the UTF-8 encoding of @scheme[str]'s
substring from @scheme[start] to @scheme[end], but without actually
generating the encoded bytes.}
@defproc[(bytes-utf-8-length [bstr bytes?]
[err-char (or/c false/c char?) #f]
[start exact-nonnegative-integer? 0]
[end exact-nonnegative-integer? (bytes-length bstr)])
exact-nonnegative-integer?]{
Returns the length in characters of the UTF-8 decoding of
@scheme[bstr]'s substring from @scheme[start] to @scheme[end], but without
actually generating the decoded characters. If @scheme[err-char] is
@scheme[#f] and the substring is not a UTF-8 encoding overall, the
result is @scheme[#f]. Otherwise, @scheme[err-char] is used to resolve
decoding errors as in @scheme[bytes->string/utf-8].}
@defproc[(bytes-utf-8-ref [bstr bytes?]
[skip exact-nonnegative-integer? 0]
[err-char (or/c false/c char?) #f]
[start exact-nonnegative-integer? 0]
[end exact-nonnegative-integer? (bytes-length bstr)])
char?]{
Returns the @scheme[skip]th character in the UTF-8 decoding of
@scheme[bstr]'s substring from @scheme[start] to @scheme[end], but without
actually generating the other decoded characters. If the substring is
not a UTF-8 encoding up to the @scheme[skip]th character (when
@scheme[err-char] is @scheme[#f]), or if the substring decoding produces
fewer than @scheme[skip] characters, the result is @scheme[#f]. If
@scheme[err-char] is not @scheme[#f], it is used to resolve decoding
errors as in @scheme[bytes->string/utf-8].}
@defproc[(bytes-utf-8-index [bstr bytes?]
[skip exact-nonnegative-integer? 0]
[err-char (or/c false/c char?) #f]
[start exact-nonnegative-integer? 0]
[end exact-nonnegative-integer? (bytes-length bstr)])
exact-nonnegative-integer?]{
Returns the offset in bytes into @scheme[bstr] at which the @scheme[skip]th
character's encoding starts in the UTF-8 decoding of @scheme[bstr]'s
substring from @scheme[start] to @scheme[end] (but without actually
generating the other decoded characters). The result is relative to
the start of @scheme[bstr], not to @scheme[start]. If the substring is not
a UTF-8 encoding up to the @scheme[skip]th character (when
@scheme[err-char] is @scheme[#f]), or if the substring decoding produces
fewer than @scheme[skip] characters, the result is @scheme[#f]. If
@scheme[err-char] is not @scheme[#f], it is used to resolve decoding
errors as in @scheme[bytes->string/utf-8].}
@; ----------------------------------------
@section{Bytes to Bytes Encoding Conversion}

View File

@ -0,0 +1,7 @@
#reader(lib "docreader.ss" "scribble")
@require["mz.ss"]
@title[#:tag "characters"]{Characters}
A @pidefterm{character} corresponds to a Unicode scalar value (i.e., a
Unicode code point that is not a surrogate).

View File

@ -0,0 +1,205 @@
#reader(lib "docreader.ss" "scribble")
@require["mz.ss"]
@title{Core Datatypes}
Each of the built-in datatypes comes with a set of procedures for
manipulating members of the datatype.
@; ------------------------------------------------------------
@section[#:tag "booleans"]{Booleans}
True and false are represented by the values @scheme[#t] and
@scheme[#f], respectively, though operations that depend a boolean
value typically treat anything other than @scheme[#f] as true.
See also: @scheme[and], @scheme[or], @scheme[andmap], @scheme[ormap].
@defproc[(boolean? [v any/c]) boolean?]{Returns @scheme[#t] if @scheme[v]
is @scheme[#t] or @scheme[#f], @scheme[#f] otherwise.}
@; ------------------------------------------------------------
@include-section["numbers.scrbl"]
@; ------------------------------------------------------------
@include-section["strings.scrbl"]
@; ------------------------------------------------------------
@include-section["bytes.scrbl"]
@; ------------------------------------------------------------
@include-section["chars.scrbl"]
@; ------------------------------------------------------------
@section[#:tag "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
interned.
@index['("symbols" "generating")]{@index['("symbols" "unique")]{The}} two
procedures @scheme[string->uninterned-symbol] and @scheme[gensym]
generate @idefterm{uninterned symbols}, i.e., a symbols that are not
@scheme[eq?], @scheme[eqv?], or @scheme[equal?] to any other symbol,
although they may print the same as other symbols.
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"]).
@defproc[(symbol? [v any/c]) boolean?]{Returns @scheme[#t] if @scheme[v] is
a symbol, @scheme[#f] otherwise.}
@examples[(symbol? 'Apple) (symbol? 10)]
@defproc[(symbol->string [sym symbol?]) symbol?]{Returns a freshly
allocated mutable string whose characters are the same as in
@scheme[sym].}
@examples[(symbol->string 'Apple)]
@defproc[(string->symbol [str string?]) symbol?]{Returns an interned
symbol whose characters are the same as in @scheme[str].}
@examples[(string->symbol "Apple") (string->symbol "1")]
@defproc[(string->uninterned-symbol [str string?]) symbol?]{Like
@scheme[(string->symbol str)], but the resulting symbol is a new
uninterned symbol. Calling @scheme[string->uninterned-symbol] twice
with the same @scheme[str] returns two distinct symbols.}
@examples[(string->uninterned-symbol "Apple") (eq? 'a (string->uninterned-symbol "a"))]
@defproc[(gensym [base (or/c string? symbol?) "g"]) symbol?]{Returns a
new uninterned symbol with an automatically-generated name. The
optional @scheme[base] argument is a prefix symbol or string.}
@examples[(gensym "apple")]
@; ------------------------------------------------------------
@section[#:tag "keywords"]{Keywords}
@; ----------------------------------------------------------------------
@section[#:tag "pairs"]{Pairs and Lists}
@defproc[(cons [a any/c] [d any/c]) pair?]{Returns a pair whose first
element is @scheme[a] and second element is @scheme[d].}
@defproc[(pair? [v any/c]) boolean?]{Returns @scheme[#t] if @scheme[v] is
a pair, @scheme[#f] otherwise.}
@defproc[(cons? [v any/c]) boolean?]{The same as @scheme[(pair? v)].}
@defproc[(car [p pair?]) any/c]{Returns the first element of the
pair @scheme[p].}
@defproc[(cdr [p pair?]) any/c]{Returns the second element of the
pair @scheme[p].}
@defproc[(first [p pair?]) any/c]{The same as @scheme[(car p)].}
@defproc[(rest [p pair?]) any/c]{The same as @scheme[(cdr p)].}
@defthing[null null?]{The empty list.}
@defthing[empty null?]{The empty list.}
@defproc[(null? [v any/c]) boolean?]{Returns @scheme[#t] if @scheme[v] is
the empty list, @scheme[#f] otherwise.}
@defproc[(empty? [v any/c]) boolean?]{The same as @scheme[(null? v)].}
@defproc[(list [v any/c] ...0) list?]{Returns a newly allocated list
containing the @scheme[v]s as its elements.}
@defproc[(map [proc procedure?] [lst (listof any/c)] ...1) (listof
any/c)]{Applies @scheme[proc] to the elements of the @scheme[lst]s from the
first elements to the last, returning @scheme[#f] as soon as any
application returns @scheme[#f]. The @scheme[proc] argument must accept
the same number of arguments as the number of supplied @scheme[lst]s,
and all @scheme[lst]s must have the same number of elements.
The result is a list containing each result of @scheme[proc].}
@defproc[(andmap [proc procedure?] [lst (listof any/c)] ...1)
any]{Similar to @scheme[map], except that
@itemize{
@item{the result is @scheme[#f] if any application of @scheme[proc] produces
@scheme[#f], in which case @scheme[proc] is not applied to later
elements of the @scheme[lst]s; or}
@item {the result is that of @scheme[proc] applied to the last elements
of the @scheme[lsts]s; more specifically, the application of
@scheme[proc] to the last elements in the @scheme[lst]s is in tail
position with respect to the @scheme[andmap] call.}
}
If the @scheme[lst]s are empty, then @scheme[#t] is returned.}
@examples[
(andmap positive? '(1 2 3))
(andmap positive? '(1 2 a))
(andmap positive? '(1 -2 a))
(andmap + '(1 2 3) '(4 5 6))
]
@defproc[(ormap [proc procedure?] [lst (listof any/c)] ...1)
any]{Similar to @scheme[map], except that
@itemize{
@item{the result is @scheme[#f] if every application of @scheme[proc] produces
@scheme[#f]; or}
@item{the result of the first applciation of @scheme[proc] to produces a
value other than @scheme[#f], in which case @scheme[proc] is not
applied to later elements of the @scheme[lst]s; more specifically,
the application of @scheme[proc] to the last elements in the
@scheme[lst]s is in tail position with respect to the
@scheme[andmap] call.}
}
If the @scheme[lst]s are empty, then @scheme[#f] is returned.}
@examples[
(ormap eq? '(a b c) '(a b c))
(ormap positive? '(1 2 a))
(ormap + '(1 2 3) '(4 5 6))
]
@defproc[(for-each [proc procedure?] [lst (listof any/c)] ...1)
void?]{Similar to @scheme[map], but @scheme[proc] is called only for
its effect, and its result (which can be any number of values) is
ignored.}
@; ----------------------------------------------------------------------
@section[#:tag "hashtables"]{Hash Tables}
@section[#:tag "procedures"]{Procedures}
@section[#:tag "promises"]{Promises}
@; ----------------------------------------------------------------------
@section[#:tag "void"]{Void and Undefined}
@defproc[(void [v any/c] ...) void?]{Returns the constant @void-const[]. Each
@scheme[v] argument is ignored.}
@defproc[(void? [v any/c]) void?]{Returns @scheme[#t] if @scheme[v] is the
constant @void-const[], @scheme[#f] otherwise.}

View File

@ -0,0 +1,17 @@
(module mz mzscheme
(require (lib "struct.ss" "scribble")
(lib "manual.ss" "scribble")
(lib "eval.ss" "scribble"))
(provide (all-from (lib "manual.ss" "scribble"))
(all-from (lib "eval.ss" "scribble")))
(define (*exnraise s)
(make-element #f (list s " exception is raised")))
(define-syntax exnraise
(syntax-rules ()
[(_ s) (*exnraise (scheme s))]))
(define-syntax Exn
(syntax-rules ()
[(_ s) (scheme s)]))
(provide exnraise Exn))

View File

@ -0,0 +1,522 @@
#reader(lib "docreader.ss" "scribble")
@require["mz.ss"]
@title[#:tag "numbers"]{Numbers}
All numbers are @idefterm{complex numbers}. Some of them are
@idefterm{real numbers}, and all of the real numbers that can be
represented are also @idefterm{rational numbers}. Among the real
numbers, some are @idefterm{integers}, because @scheme[round] applied
to the number produces the same number.
Orthogonal to those categories, each number is also either
@idefterm{exact} or @idefterm{inexact}. Unless otherwise specified,
computations that involve an inexact number produce inexact results,
so that inexactness acts as a kind of taint on numbers. Certain
operations on inexact numbers, however, produce an exact number, such
as multiplying an inexact number with an exact @scheme[0]. Some
operations, which can produce an irrational number for rational
arguments (e.g., @scheme[sqrt]), may produce inexact results even for
exact arguments.
In the case of complex numbers, either the real and imaginary parts
are both exact or inexact, or the number has an exact zero real part
and an inexact imaginary part; a complex number with an zero imaginary
part (inexact or exact) is a real number.
Inexact real numbers are implemented as either single- or
double-precision IEEE floating-point numbers---the latter by default,
and the former only when support for 32-bit inexact numbers is
specifically enabled when the run-time system is built, and when
computation starts with numerical constants specified as
single-precision numbers.
The precision and size of exact numbers is limited only by available
memory (and the precision of operations that can produce irrational
numbers). In particular, adding, multiplying, subtracting, and
dividing exact numbers always produces an extract result.
@index["division by inexact zero"]{Inexact} numbers can be coerced to
exact form, except for the inexact numbers @as-index{@scheme[+inf.0]}
(positive infinity), @as-index{@scheme[-inf.0]} (negative infinity), and
@as-index{@scheme[+nan.0]} (not-a-number), which have no exact
form. Dividing a number by exact zero raises an exception; dividing a
non-zero number other than @scheme[+nan.0] by an inexact zero returns
@scheme[+inf.0] or @scheme[-inf.0], depending on the sign of the
dividend. The infinities @scheme[+inf.0] and @scheme[-inf.0] are
integers, and they answer @scheme[#t] for both @scheme[even?] and
@scheme[odd?]. The @scheme[+nan.0] value is not an integer and is not
@scheme[=] to itself, but @scheme[+nan.0] is @scheme[eqv?] to
itself. Conversely, @scheme[(= 0.0 -0.0)] is @scheme[#t], but
@scheme[(eqv? 0.0 -0.0)] is @scheme[#f]. The datum @scheme[-nan.0]
refers to the same constant as @scheme[+nan.0].
Calculations with infinites produce results consistent with IEEE
double-precision floating point where IEEE specifies the result; in
cases where IEEE provides no specification (e.g., @scheme[(angle
+inf.0+inf.0)]), the result corresponds to the limit approaching
infinity, or @scheme[+nan.0] if no such limit exists.
A @pidefterm{fixnum} is an exact integer whose two's complement
representation fit into 31 bits on a 32-bit platform or 63 bits on a
64-bit platform. Two fixnums that are @scheme[=] are also the same
according to @scheme[eq?]. Otherwise, the result of @scheme{eq?}
applied to two numbers is undefined.
Two numbers are @scheme[eqv?] when they are both inexact or both
exact, and when they are @scheme[=] (except for @scheme[+nan.0], as
noted above). Two numbers are @scheme[equal?] when they are
@scheme[eqv?].
@defproc[(number? [v any/c]) boolean?]{ Returns @scheme[#t] if @scheme[v]
is a number, @scheme[#f] otherwise.
@examples[(number? 1) (number? 2+3i) (number? "hello")]}
@defproc[(complex? [v any/c]) boolean?]{ Returns @scheme[(number? #,
@scheme[v])], because all numbers are complex numbers.}
@defproc[(real? [v any/c]) boolean?]{ Returns @scheme[#t] if @scheme[v] is
a real number, @scheme[#f] otherwise. A number with an inexact zero
imaginary part is a real number.
@examples[(real? 1) (real? 2+3i) (real? "hello")]}
@defproc[(rational? [v any/c]) boolean?]{ Returns @scheme[(real? #,
@scheme[v])].}
@defproc[(integer? [v any/c]) boolean?]{ Returns @scheme[#t] if @scheme[v]
is a number that is an integer, @scheme[#f] otherwise. The inexact
numbers @scheme[+inf.0] and @scheme[-inf.0] are integers, but
@scheme[+nan.0] is not.
@examples[(integer? 1) (integer? 2.3) (integer? 4.0) (integer? 2+3i) (integer? "hello")]}
@defproc[(exact? [z number?]) boolean?]{ Returns @scheme[#t] if @scheme[z]
is an exact number, @scheme[#f] otherwise.
@examples[(exact? 1) (exact? 1.0)]}
@defproc[(inexact? [z number?]) boolean?]{ Returns @scheme[#t] if @scheme[z]
is an inexact number, @scheme[#f] otherwise.
@examples[(inexact? 1) (inexact? 1.0)]}
@defproc[(inexact->exact [z number?]) exact?]{ Coerces @scheme[z] to an
exact number. If @scheme[z] is already exact, it is returned. If @scheme[z]
is @scheme[+inf.0], @scheme[-inf.0], or @scheme[+nan.0], then the
@exnraise[exn:fail:contract].
@examples[(inexact->exact 1) (inexact->exact 1.0)]}
@defproc[(exact->inexact [z number?]) inexact?]{ Coerces @scheme[z] to an
inexact number. If @scheme[z] is already inexact, it is returned.
@examples[(exact->inexact 1) (exact->inexact 1.0)]}
@defproc[(+ [z number?] ...0) number?]{ Returns the sum of the
@scheme[z]s, adding pairwise from left to right. If no arguments are
provided, the result is @scheme[0].
@examples[(+ 1 2) (+ 1.0 2+3i 5) (+)]}
@defproc*[([(- [z number?]) number?]
[(- [z number?] [w number?] ...1) number?])]{
When no @scheme[w]s are supplied, returns @scheme[(- 0 #, @scheme[z])].
Otherwise, returns the subtraction of the @scheme[w]s from @scheme[z]
working pairwise from left to right.}
@examples[(- 5 3.0) (- 1) (- 2+7i 1 3)]
@defproc[(* [z number?] ...0) number?]{ Returns the product of the
@scheme[z]s, multiplying pairwise from left to right. If no arguments are
provided, the result is @scheme[1].}
@examples[(* 2 3) (* 8.0 9) (* 1+2i 3+4i)]
@defproc*[([(/ [z number?]) number?]
[(/ [z number?] [w number?] ...1) number?])] {
When no @scheme[w]s are supplied, returns @scheme[(/ 1 #, @scheme[z])].
Otherwise, returns the division @scheme[z] by the var[w]s
working pairwise from left to right.}
@examples[(/ 3 4) (/ 81 3 3) (/ 10.0) (/ 1+2i 3+4i)]
@defproc[(quotient [n integer?] [m integer?]) number?]{ 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
@scheme[q] with the same sign as @scheme[n] such that
@itemize{
@item{@scheme[(abs q)] is between @scheme[0] (inclusive) and @scheme[(abs m)] (exclusive), and}
@item{@scheme[(+ q (* m (quotient n m)))] equals @scheme[n].}
}
@examples[(remainder 10 3) (remainder -10.0 3) (remainder 10.0 -3) (remainder -10 -3) (remainder +inf.0 3)]}
@defproc[(modulo [n integer?] [m integer?]) number?]{ Returns
@scheme[q] with the same sign as @scheme[m] where
@itemize{
@item{@scheme[(abs q)] is between @scheme[0] (inclusive) and @scheme[(abs m)] (exclusive), and}
@item{the difference between @scheme[q] and @scheme[(- n (* m (quotient n m)))] is a multiple of @scheme[m].}
}
@examples[(modulo 10 3) (modulo -10.0 3) (modulo 10.0 -3) (modulo -10 -3) (modulo +inf.0 3)]}
@defproc[(add1 [z number?]) number?]{ Returns @scheme[(+ z 1)].}
@defproc[(sub1 [z number?]) number?]{ Returns @scheme[(- z 1)].}
@defproc[(abs [x real?]) number?]{ Returns the absolute value of
@scheme[x].
@examples[(abs 1.0) (abs -1)]}
@defproc[(= [z number?] [w number?] ...1) boolean?]{ Returns
@scheme[#t] if all of the arguments are numerically equal,
@scheme[#f] otherwise. An inexact number is numerically equal to an
exact number when the exact coercion of the inexact number is the
exact number. Also, @scheme[0.0] and @scheme[-0.0] are numerically
equal, but @scheme[+nan.0] is not numerically equal to itself.
@examples[(= 1 1.0) (= 1 2) (= 2+3i 2+3i 2+3i)]}
@defproc[(< [x real?] [y real?] ...1) boolean?]{ Returns @scheme[#t] if
the arguments in the given order are in strictly increasing,
@scheme[#f] otherwise.
@examples[(< 1 1) (< 1 2 3) (< 1 +inf.0) (< 1 +nan.0)]}
@defproc[(<= [x real?] [y real?] ...1) boolean?]{ Returns @scheme[#t]
if the arguments in the given order are in non-decreasing,
@scheme[#f] otherwise.
@examples[(<= 1 1) (<= 1 2 1)]}
@defproc[(> [x real?] [y real?] ...1) boolean?]{ Returns @scheme[#t] if
the arguments in the given order are in strictly decreasing,
@scheme[#f] otherwise.
@examples[(> 1 1) (> 3 2 1) (> +inf.0 1) (< +nan.0 1)]}
@defproc[(>= [x real?] [y real?] ...1) boolean?]{ Returns @scheme[#t]
if the arguments in the given order are in non-increasing,
@scheme[#f] otherwise.
@examples[(>= 1 1) (>= 1 2 1)]}
@defproc[(zero? [z number?]) boolean?]{ Returns @scheme[(= 0 z)].
@examples[(zero? 0) (zero? -0.0)]}
@defproc[(positive? [x real?]) boolean?]{ Returns @scheme[(> x 0)].
@examples[(positive? 10) (positive? -10) (positive? 0.0)]}
@defproc[(negative? [x real?]) boolean?]{ Returns @scheme[(< x 0)].
@examples[(negative? 10) (negative? -10) (negative? -0.0)]}
@defproc[(max [x real?] ...1) boolean?]{ Returns the largest of the
@scheme[x]s, or @scheme[+nan.0] if any @scheme[x] is @scheme[+nan.0].
If any @scheme[x] is inexact, the result is coerced to inexact.
@examples[(max 1 3 2) (max 1 3 2.0)]}
@defproc[(min [x real?] ...1) boolean?]{ Returns the smallest of the
@scheme[x]s, or @scheme[+nan.0] if any @scheme[x] is @scheme[+nan.0].
If any @scheme[x] is inexact, the result is coerced to inexact.
@examples[(min 1 3 2) (min 1 3 2.0)]}
@defproc[(even? [n integer?]) boolean?]{ Returns @scheme[(zero? (modulo
n 2))].
@examples[(even? 10.0) (even? 11) (even? +inf.0)]}
@defproc[(odd? [n integer?]) boolean?]{ Returns @scheme[(not (even? n))].
@examples[(odd? 10.0) (odd? 11) (odd? +inf.0)]}
@defproc[(gcd [n integer?] ...0) integer?]{ Returns the greatest common
divisor of the @scheme[n]s. If no arguments are provided, the result is
@scheme[0].
@examples[(gcd 10) (gcd 12 81.0)]}
@defproc[(lcm [n integer?] ...0) integer?]{ Returns the least common
multiple of the @scheme[n]s. If no arguments are provided, the result is
@scheme[1].
@examples[(lcm 10) (lcm 3 4.0)]}
@defproc[(round [x real?]) integer?]{ Returns the integer closest to
@scheme[x], resolving ties in favor of an even number.
@examples[(round 17/4) (round -17/4) (round 2.5) (round -2.5)]}
@defproc[(floor [x real?]) integer?]{ Returns the largest integer is that
is no more than @scheme[x].
@examples[(floor 17/4) (floor -17/4) (floor 2.5) (floor -2.5)]}
@defproc[(ceiling [x real?]) integer?]{ Returns the smallest integer is
that is at least as large as @scheme[x].
@examples[(ceiling 17/4) (ceiling -17/4) (ceiling 2.5) (ceiling -2.5)]}
@defproc[(truncate [x real?]) integer?]{ Returns the integer farthest
from @scheme[0] that is no closer to @scheme[0] than @scheme[x].
@examples[(truncate 17/4) (truncate -17/4) (truncate 2.5) (truncate -2.5)]}
@defproc[(numerator [x real?]) (or integer? (one-of/c +nan.0))]{
Coreces @scheme[x] to an exact number, finds the numerator of the number
expressed in its simplest fractional form, and returns this number
coerced to the exactness of @scheme[x]. An exception is when @scheme[x] is
@scheme[+inf.0], @scheme[-inf.0], and @scheme[+nan.0], in which case
@scheme[x] is returned.
@examples[(numerator 5) (numerator 34/8) (numerator 2.3) (numerator +inf.0)]}
@defproc[(denominator [x real?]) (or/c integer? (one-of/c +nan.0))]{
Coreces @scheme[x] to an exact number, finds the numerator of the number
expressed in its simplest fractional form, and returns this number
coerced to the exactness of @scheme[x]. Exceptions are when @scheme[x] is
@scheme[+inf.0] or @scheme[-inf.0], in which case @scheme[1.0] is
returned, or when @scheme[x] is @scheme[+nan.0], in which case
@scheme[+nan.0] is returned.
@examples[(denominator 5) (denominator 34/8) (denominator 2.3) (denominator +inf.0)]}
@defproc[(exp [z number?]) number?]{ Returns Euler's number raised to the
power of @scheme[z]. The result is normally inexact, but it is
@scheme[1] when @scheme[z] is an exact @scheme[0].
@examples[(exp 1) (exp 2+3i) (exp 0)]}
@defproc[(log [z number?]) number?]{ Returns the natural logarithm of
@scheme[z]. The result is normally inexact, but it is
@scheme[0] when @scheme[z] is an exact @scheme[1].
@examples[(log (exp 1)) (log 2+3i) (log 1)]}
@defproc[(sin [z number?]) number?]{ Returns the sine of @scheme[z], where
@scheme[z] is in radians.
@examples[(sin 3.14159) (sin 1+05.i)]}
@defproc[(cos [z number?]) number?]{ Returns the cosine of @scheme[z],
where @scheme[z] is in radians.
@examples[(cos 3.14159) (cos 1+05.i)]}
@defproc[(tan [z number?]) number?]{ Returns the tangent of @scheme[z],
where @scheme[z] is in radians.
@examples[(tan 0.7854) (tan 1+05.i)]}
@defproc[(asin [z number?]) number?]{ Returns the arcsin in radians of @scheme[z].
@examples[(asin 0.25) (asin 1+05.i)]}
@defproc[(acos [z number?]) number?]{ Returns the arccosine in radians
of @scheme[z].
@examples[(acos 0.25) (acos 1+05.i)]}
@defproc*[([(atan [z number?]) number?]
[(atan [y real?] [x real?]) number?])]{Returns the arctangent of
@scheme[z] or of @scheme[(make-rectangular #, @scheme[x] #, @scheme[y])].}
@examples[(atan 0.5) (atan 2 1) (atan -2 -1) (atan 1+05.i)]
@defproc[(sqrt [z number?]) number?]{ Returns the principal square root
of @scheme[z].The result is exact if @scheme[z] is exact and @scheme[z]'s
square root is rational.
@examples[(sqrt 4/9) (sqrt 2) (sqrt -1)]}
@defproc[(integer-sqrt [n integer?]) integer?]{ Returns @scheme[(floor
(sqrt n))] for positive @scheme[n]. For negative @scheme[n], the result is
@scheme[(* (integer-sqrt (- n)) 0+i)].
@examples[(integer-sqrt 4.0) (integer-sqrt 5)]}
@defproc[(integer-sqrt/remainder [n integer?]) (values integer?
integer?)]{ Returns @scheme[(integer-sqrt n)] and @scheme[(- n (expt
(integer-sqrt n) 2))].
@examples[(integer-sqrt/remainder 4.0) (integer-sqrt/remainder 5)]}
@defproc[(expt [z number?] [w number?]) number?]{ Returns @scheme[z]
raised to the power of @scheme[w]. If @scheme[w] is exact @scheme[0],
the result is @scheme[1]. If @scheme[z] is exact @scheme[0] and
@scheme[w] is negative, the @exnraise[exn:fail:contract].
@examples[(expt 2 3) (expt 4 0.5) (expt +inf.0 0)]}
@defproc[(make-rectangular [x real?] [y real?]) number?]{ Returns
@scheme[(+ x (* y 0+1i))].
@examples[(make-rectangular 3 4.0)]}
@defproc[(make-polar [x real?] [y real?]) number?]{ Returns
@scheme[(+ (* x (cos y)) (* x (sin y) 0+1i))].
@examples[(make-polar 2 3.14159)]}
@defproc[(real-part [z number?]) real?]{ Returns the real part of
the complex number @scheme[z] in rectangle coordinates.
@examples[(real-part 3+4i) (real-part 5.0)]}
@defproc[(imag-part [z number?]) real?]{ Returns the imaginary part of
the complex number @scheme[z] in rectangle coordinates.
@examples[(imag-part 3+4i) (imag-part 5.0) (imag-part 5.0+0.0i)]}
@defproc[(magnitude [z number?]) real?]{ Returns the magnitude of
the complex number @scheme[z] in polar coordinates.
@examples[(magnitude -3) (magnitude 3.0) (magnitude 3+4i)]}
@defproc[(angle [z number?]) real?]{ Returns the angle of
the complex number @scheme[z] in polar coordinates.
@examples[(angle -3) (angle 3.0) (angle 3+4i) (angle +inf.0+inf.0i)]}
@defproc[(bitwise-ior [n exact-integer?] ...0) exact-integer?]{ Returns
the bitwise ``inclusive or'' of the @scheme[n]s in their (semi-infinite)
two's complement representation. If no arguments are provided, the
result is @scheme[0].
@examples[(bitwise-ior 1 2) (bitwise-ior -32 1)]}
@defproc[(bitwise-and [n exact-integer?] ...0) exact-integer?]{ Returns
the bitwise ``and'' of the @scheme[n]s in their (semi-infinite) two's
complement representation. If no arguments are provided, the result
is @scheme[-1].
@examples[(bitwise-and 1 2) (bitwise-and -32 -1)]}
@defproc[(bitwise-xor [n exact-integer?] ...0) exact-integer?]{ Returns
the bitwise ``exclusive or'' of the @scheme[n]s in their (semi-infinite)
two's complement representation. If no arguments are provided, the
result is @scheme[0].
@examples[(bitwise-xor 1 5) (bitwise-xor -32 -1)]}
@defproc[(bitwise-not [n exact-integer?]) exact-integer?]{ Returns the
bitwise ``not'' of @scheme[n] in its (semi-infinite) two's complement
representation.
@examples[(bitwise-not 5) (bitwise-not -1)]}
@defproc[(arithmetic-shift [n exact-integer?] [m exact-integer?])
exact-integer?]{ Returns the bitwise ``shift'' of @scheme[n] in its
(semi-infinite) two's complement representation. If @scheme[m] is
non-negative, the integer @scheme[n] is shifted left by @scheme[m] bits;
i.e., @scheme[m] new zeros are introduced as rightmost digits. If
@scheme[m] is negative, @scheme[n] is shifted right by @scheme[(- #,
@scheme[m])] bits; i.e., the rightmost @scheme[m] digits are dropped.
@examples[(arithmetic-shift 1 10) (arithmetic-shift 255 -3)]}
@defproc[(integer-length [n exact-integer?]) exact-integer?]{ Returns
the number of bits in the (semi-infinite) two's complement
representation of @scheme[n] after removing all leading zeros (for
non-negative @scheme[n]) or ones (for negative @scheme[n]).
@examples[(integer-length 8) (integer-length -8)]}
@defproc[(number->string [z number?] [radix (one-of/c 2 8 10
16) 10]) string?]{ Returns a string that is the printed form of @scheme[z]
in the base specific by @scheme[radix]. If @scheme[z] is inexact,
@scheme[radix] must be @scheme[10], otherwise the
@exnraise[exn:fail:contract].
@examples[(number->string 3.0) (number->string 255 8)]}
@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] 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},
@litchar{#o}, @litchar{#d}, or @litchar{#x} in the string.
@examples[(string->number "3.0+2.5i") (string->number "hello")
(string->number "111" 7) (string->number "#b111" 7)]
}

View File

@ -0,0 +1,717 @@
#reader(lib "docreader.ss" "scribble")
@require["mz.ss"]
@require[(lib "bnf.ss" "scribble")]
@require["reader-example.ss"]
@begin[
(define (ilitchar s)
(litchar s))
(define (nunterm s)
(nonterm s (subscript "n")))
(define (sub n) (subscript n))
(define (nonalpha)
@elem{; the next character must not be @schemelink[char-alphabetic?]{alphabetic}.})
]
@define[(graph-tag) @kleenerange[1 8]{@nonterm{digit@sub{10}}}]
@define[(graph-defn) @elem{@litchar{#}@graph-tag[]@litchar{=}}]
@define[(graph-ref) @elem{@litchar{#}@graph-tag[]@litchar{#}}]
@title{Syntax}
The syntax of a Scheme program is defined by
@itemize{
@item{a @defterm{read} phase that processes a character stream into
an S-expression, and}
@item{an @defterm{expand} phase that processes the S-expression based
on bindings in the lexical environment, where some parsing
steps can introduce new bindings for further parsing steps.}
}
Note that parsing is defined in terms of Unicode characters; see
@secref["unicode"] for information on how a byte stream is converted
to a character stream.
@section[#:tag "reader"]{Reading Data}
Scheme's reader is a recursive-descent parser that can be configured
through a @seclink["readtable"]{readtable} and various other
@seclink["parameters"]{parameters}. This section describes the reader's
parsing when using the default readtable.
Reading from a stream produces one datum. If the result datum is a
compound value, then reading the datum typically requires the reader
to call itself recursively to read the component data.
The reader can be invoked in either of two modes: @scheme[read] mode,
or @scheme[read-syntax] mode. In @scheme[read-syntax] mode, the result
is always a @seclink["stxobj"]{syntax object} that includes
source-location information wrapped around the sort of datum that
@scheme[read] mode would produce. In the case of pairs, vectors, and
boxes, morever, the content is also wrapped recursively as a syntax
object. Unless specified otherwise, this section describes the
reader's behavior in @scheme[read] mode, and @scheme[read-syntax] mode
does the same modulo wrapping the final result.
@subsection{Delimiters and Dispatch}
Along with @schemelink[char-whitespace?]{whitespace}, the following
characters are @defterm{delimiters}:
@t{
@hspace[2] @ilitchar{(} @ilitchar{)} @ilitchar{[} @ilitchar{]}
@ilitchar["["] @ilitchar["]"]
@ilitchar{"} @ilitchar{,} @ilitchar{'} @ilitchar{`}
@ilitchar{;}
}
A delimited sequence that starts with any other character is typically
parsed as either a symbol or number, but a few non-delimiter
characters play special roles:
@itemize{
@item{@litchar{#} has a special meaning as an initial character in a
delimited sequence; its meaning depends on the characters that
follow; see below.}
@item{@as-index{@litchar["|"]} starts a subsequence of characters to
be included verbatim in the delimited sequence (i.e,. they are
never treated as delimiters, and they are not case-folded when
case-insensitivity is enabled); the subsequence is terminated
by another @litchar["|"], and neither the initial nor
terminating @litchar["|"] is part of the subsequence.}
@item{@as-index{@litchar["\\"]} outside of a @litchar["|"] pair causes
the folowing character to be included verbatim in a delimited
sequence.}
}
More precisely, after skipping whitespace, the reader dispatches based
on the next character or characters in the input stream as follows:
@dispatch-table[
@dispatch[@litchar{(}]{starts a pair or list; see @secref["parse-pair"]}
@dispatch[@litchar{[}]{starts a pair or list; see @secref["parse-pair"]}
@dispatch[@litchar["{"]]{starts a pair or list; see @secref["parse-pair"]}
@dispatch[@litchar{)}]{matches @litchar{(} or raises @Exn{exn:fail:read}}
@dispatch[@litchar{]}]{matches @litchar{[} or raises @Exn{exn:fail:read}}
@dispatch[@litchar["}"]]{matches @litchar["{"] or raises @Exn{exn:fail:read}}
@dispatch[@litchar{"}]{starts a string; see @secref["parse-string"]}
@dispatch[@litchar{,}]{starts a quote; see @secref["parse-quote"]}
@dispatch[@litchar{`}]{starts a quasiquote; see @secref["parse-quote"]}
@dispatch[@litchar{,}]{starts an unquote or splicing unquote; see @secref["parse-quote"]}
@dispatch[@litchar{;}]{starts a line comment; see @secref["parse-comment"]}
@dispatch[@cilitchar{#t}]{true; see @secref["parse-boolean"]}
@dispatch[@cilitchar{#f}]{false; see @secref["parse-boolean"]}
@dispatch[@litchar{#(}]{starts a vector; see @secref["parse-vector"]}
@dispatch[@litchar{#[}]{starts a vector; see @secref["parse-vector"]}
@dispatch[@litchar["#{"]]{starts a vector; see @secref["parse-vector"]}
@dispatch[@litchar["#\\"]]{starts a character; see @secref["parse-character"]}
@dispatch[@litchar{#"}]{starts a byte string; see @secref["parse-string"]}
@dispatch[@litchar{#%}]{starts a symbol; see @secref["parse-symbol"]}
@dispatch[@litchar{#:}]{starts a keyword; see @secref["parse-keyword"]}
@dispatch[@litchar{#&}]{starts a box; see @secref["parse-box"]}
@dispatch[@litchar["#|"]]{starts a block comment; see @secref["parse-comment"]}
@dispatch[@litchar["#;"]]{starts an S-expression comment; see @secref["parse-comment"]}
@dispatch[@litchar{#,}]{starts a syntax quote; see @secref["parse-quote"]}
@dispatch[@litchar{#`}]{starts a syntax quasiquote; see @secref["parse-quote"]}
@dispatch[@litchar{#,}]{starts an syntax unquote or splicing unquote; see @secref["parse-quote"]}
@dispatch[@litchar["#~"]]{starts compiled code; see @secref["compilation"]}
@dispatch[@cilitchar{#i}]{starts a number; see @secref["parse-number"]}
@dispatch[@cilitchar{#e}]{starts a number; see @secref["parse-number"]}
@dispatch[@cilitchar{#x}]{starts a number; see @secref["parse-number"]}
@dispatch[@cilitchar{#o}]{starts a number; see @secref["parse-number"]}
@dispatch[@cilitchar{#d}]{starts a number; see @secref["parse-number"]}
@dispatch[@cilitchar{#b}]{starts a number; see @secref["parse-number"]}
@dispatch[@cilitchar["#<<"]]{starts a string; see @secref["parse-string"]}
@dispatch[@litchar{#rx}]{starts a regular expression; see @secref["parse-regexp"]}
@dispatch[@litchar{#px}]{starts a regular expression; see @secref["parse-regexp"]}
@dispatch[@cilitchar{#ci}]{switches case sensitivity; see @secref["parse-symbol"]}
@dispatch[@cilitchar{#cs}]{switches case sensitivity; see @secref["parse-symbol"]}
@dispatch[@cilitchar["#sx"]]{starts a Scheme expression; see @secref["parse-honu"]}
@dispatch[@litchar["#hx"]]{starts a Honu expression; see @secref["parse-honu"]}
@dispatch[@litchar["#honu"]]{starts a Honu module; see @secref["parse-honu"]}
@dispatch[@litchar["#hash"]]{starts a hash table; see @secref["parse-hashtable"]}
@dispatch[@litchar["#reader"]]{starts a reader extension use; see @secref["parse-reader"]}
@dispatch[@elem{@litchar{#}@kleeneplus{@nonterm{digit@sub{10}}}@litchar{(}}]{starts a vector; see @secref["parse-vector"]}
@dispatch[@elem{@litchar{#}@kleeneplus{@nonterm{digit@sub{10}}}@litchar{[}}]{starts a vector; see @secref["parse-vector"]}
@dispatch[@elem{@litchar{#}@kleeneplus{@nonterm{digit@sub{10}}}@litchar["{"]}]{starts a vector; see @secref["parse-vector"]}
@dispatch[@graph-defn[]]{binds a graph tag; see @secref["parse-graph"]}
@dispatch[@graph-ref[]]{uses a graph tag; see @secref["parse-graph"]}
@dispatch[@italic{otherwise}]{starts a symbol; see @secref["parse-symbol"]}
]
@subsection[#:tag "parse-symbol"]{Reading Symbols}
A sequence that does not start with a delimiter or @litchar{#} is
parsed as either a symbol or a number (see @secref["parse-number"]),
except that @litchar{.} by itself is never parsed as a symbol or
character. A @as-index{@litchar{#%}} also starts a symbol. A successful
number parse takes precedence over a symbol parse.
When the @scheme[read-case-sensitive] parameter is set to @scheme[#f],
characters in the sequence that are not quoted by @litchar["|"] or
@litchar["\\"] are first case-normalized. If the reader encounters
@as-index{@litchar{#ci}}, @litchar{#CI}, @litchar{#Ci}, or @litchar{#cI},
then it recursively reads the following datum in
case-insensitive mode. If the reader encounters @as-index{@litchar{#cs}},
@litchar{#CS}, @litchar{#Cs}, or @litchar{#cS}, then recursively reads
the following datum in case-sensitive mode.
@reader-examples[
"Apple"
"Ap#ple"
"Ap ple"
"Ap| |ple"
"Ap\\ ple"
"#ci Apple"
"#ci |A|pple"
"#ci \\Apple"
"#ci#cs Apple"
"#%Apple"
]
@subsection[#:tag "parse-number"]{Reading Numbers}
@index['("numbers" "parsing")]{A} sequence that does not start with a
delimiter is parsed as a number when it matches the following grammar
case-insenstively for @nonterm{number@sub{10}} (decimal), where
@metavar{n} is a meta-meta-variable in the grammar.
A number is optionally prefixed by an exactness specifier,
@as-index{@litchar{#e}} (exact) or @as-index{@litchar{#i}} (inexact),
which specifies its parsing as an exact or inexact number; see
@secref["numbers"] for information on number exactness. As the
non-terminal names suggest, a number that has no exactness specifier
and matches only @nunterm{inexact-number} is normally parsed as an
inexact number, otherwise it is parsed as an excat number. If the
@scheme[read-decimal-as-inexact] parameter is set to @scheme[#f], then
all numbers without an exactness specifier are instead parsed as
exact.
If the reader encounters @as-index{@litchar{#b}} (binary),
@as-index{@litchar{#o}} (octal), @as-index{@litchar{#d}} (decimal), or
@as-index{@litchar{#x}} (hexadecimal), it must be followed by a
sequence that is terminated by a delimiter or end-of-file, and that
matches the @nonterm{general-number@sub{2}},
@nonterm{general-number@sub{8}}, @nonterm{general-number@sub{10}}, or
@nonterm{general-number@sub{16}} grammar, respectively.
An @nunterm{exponent-mark} in an inexact number serves both to specify
an exponent and specify a numerical precision. If single-precision
IEEE floating point is supported (see @secref["number"]), the marks
@litchar{f} and @litchar{s} specifies single-precision. Otherwise, or
with any other mark, double-precision IEEE floating point is used.
@BNF[(list @nunterm{number} @BNF-alt[@nunterm{exact-number}
@nunterm{inexact-number}])
(list @nunterm{exact-number} @BNF-alt[@nunterm{exact-integer}
@nunterm{exact-rational}
@nunterm{exact-complex}])
(list @nunterm{exact-integer} @BNF-seq[@optional{@nonterm{sign}} @nunterm{unsigned-exact-integer}])
(list @nunterm{unsigned-exact-integer} @kleeneplus{@nunterm{digit}})
(list @nunterm{exact-rational} @BNF-seq[@nunterm{exact-integer} @litchar{/} @nunterm{unsigned-exact-integer}])
(list @nunterm{exact-complex} @BNF-seq[@nunterm{exact-rational} @nonterm{sign} @nunterm{exact-rational} @litchar{i}])
(list @nunterm{inexact-number} @BNF-alt[@nunterm{inexact-real}
@nunterm{inexact-complex}])
(list @nunterm{inexact-real} @BNF-seq[@optional{@nonterm{sign}} @nunterm{inexact-normal-real}]
@BNF-seq[@nonterm{sign} @nunterm{inexact-special-real}])
(list @nunterm{inexact-unsigned-real} @BNF-alt[@nunterm{inexact-normal-real}
@nunterm{inexact-special-real}])
(list @nunterm{inexact-normal-real} @BNF-seq[@nunterm{inexact-simple-real} @optional{@nunterm{exponent-mark}
@optional[@nonterm{sign}] @nunterm{inexact-base}}])
(list @nunterm{inexact-simple-real} @BNF-seq[@nunterm{inexact-base} @optional{@litchar{.}} @kleenestar{@litchar{#}}]
@BNF-seq[@optional{@nunterm{exact-integer}} @litchar{.} @nunterm{inexact-base}]
@BNF-seq[@nunterm{inexact-base} @litchar{/} @nunterm{inexact-base}])
(list @nunterm{inexact-special-real} @BNF-alt[@litchar{inf.0} @litchar{nan.0}])
(list @nunterm{inexact-base} @BNF-seq[@kleeneplus{@nunterm{digit}} @kleenestar{@litchar{#}}])
(list @nunterm{inexact-complex} @BNF-seq[@optional{@nunterm{inexact-real}} @nonterm{sign} @nunterm{inexact-unsigned-real} @litchar{i}]
@BNF-seq[@nunterm{inexact-real} @litchar["@"] @nunterm{inexact-real}])
(list @nonterm{sign} @BNF-alt[@litchar{+}
@litchar{-}])
(list @nonterm{digit@sub{16}} @BNF-alt[@nonterm{digit@sub{10}} @litchar{a} @litchar{b} @litchar{c} @litchar{d}
@litchar{e} @litchar{f}])
(list @nonterm{digit@sub{10}} @BNF-alt[@nonterm{digit@sub{8}} @litchar{8} @litchar{9}])
(list @nonterm{digit@sub{8}} @BNF-alt[@nonterm{digit@sub{2}} @litchar{2} @litchar{3}
@litchar{4} @litchar{5} @litchar{6} @litchar{7}])
(list @nonterm{digit@sub{2}} @BNF-alt[@litchar{0} @litchar{1}])
(list @nonterm{exponent-mark@sub{16}} @BNF-alt[@litchar{s} @litchar{d} @litchar{l}])
(list @nonterm{exponent-mark@sub{10}} @BNF-alt[@nonterm{exponent-mark@sub{16}} @litchar{e} @litchar{f}])
(list @nonterm{exponent-mark@sub{8}} @nonterm{exponent-mark@sub{10}})
(list @nonterm{exponent-mark@sub{2}} @nonterm{exponent-mark@sub{10}})
(list @nunterm{general-number} @BNF-seq[@optional{@nonterm{exactness}} @nunterm{number}])
(list @nunterm{exactness-number} @BNF-alt[@litchar{#e} @litchar{#i}])
]
@reader-examples[
"-1"
"1/2"
"1.0"
"1+2i"
"1/2+3/4i"
"1.0+3.0e7i"
"2e5"
"#i5"
"#e2e5"
"#x2e5"
"#b101"
]
@subsection[#:tag "parse-boolean"]{Reading Booleans}
A @as-index{@litchar{#t}} or @as-index{@litchar{#T}} is the complete
input syntax for the boolean constant true, and
@as-index{@litchar{#f}} or @as-index{@litchar{#F}} is the complete
input syntax for the boolean constant false.
@subsection[#:tag "parse-pair"]{Reading Pairs and Lists}
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
and lists.
To parse the pair or list, the reader recursively reads data
until a matching @as-index{@litchar{)}}, @as-index{@litchar{]}}, or
@as-index{@litchar["}"]} (respectively) is found, and it specially handles
a delimited @litchar{.}. Pairs @litchar{()}, @litchar{[]}, and
@litchar["{}"] are treated the same way, so the remainder of this
section simply uses ``parentheses'' to mean any of these pair.
If the reader finds no delimited @as-index{@litchar{.}} among the elements
between parentheses, then it produces a list containing the results of
the recursive reads.
If the reader finds two data between the matching parentheses
that are separated by a delimited @litchar{.}, then it creates a
pair. More generally, if it finds two or more data where the
last is preceeded by a delimited @litchar{.}, then it constructs
nested pairs: the next-to-last element is paired with the last, then
the third-to-last is paired with that pair, and so on.
If the reader finds three or more data between the matching
parentheses, and if a pair of delimited @litchar{.}s surrounds any
oter than the first and last elements, the result is a list
countaining the element surrounded by @litchar{.}s as the first
element, followed by the others in ther read order. This convention
supports a kind of @index["infix"]{infix} notation at the reader
level.
In @scheme[read-syntax] mode, the recursive reads for the pair/list
elements are themselves in @scheme[read-syntax] mode, so that the
result is list or pair of syntax objects that it itself wrapped as a
syntax object. If the reader constructs nested pairs because the input
included a single delimited @litchar{.}, then only the innermost pair
and outtermost pair are wrapped as syntax objects. Whether wrapping a
pair or list, if the pair or list was formed with @litchar{[} and
@litchar{]}, then a @scheme['paren-shape] property is attached to the
result with the value @scheme[#\[];if the list or pair was formed with
@litchar["{"] and @litchar["}"], then a @scheme['paren-shape] property
is attached to the result with the value @scheme[#\{].
If a delimited @litchar{.} appears in any other configuration, then
the @exnraise[exn:fail:read]. Similarly, if the reader encounters a
@litchar{)}, @litchar["]"], or @litchar["}"] that does not end a list
being parsed, then the @exnraise[exn:fail:read].
@reader-examples[
"()"
"(1 2 3)"
"{1 2 3}"
"[1 2 3]"
"(1 (2) 3)"
"(1 . 3)"
"(1 . (3))"
"(1 . 2 . 3)"
]
If the @scheme[read-square-bracket-as-paren] parameter is set to
@scheme[#f], then when then reader encounters @litchar{[} and
@litchar{]}, the @exnraise{exn:fail:read}. Similarly, If the
@scheme[read-curly-brace-as-paren] parameter is set to @scheme[#f],
then when then reader encounters @litchar["{"] and @litchar["}"], the
@exnraise{exn:fail:read}.
@subsection[#:tag "parse-string"]{Reading Strings}
@index['("strings" "parsing")]{When} the reader encouters
@as-index{@litchar{"}}, it begins parsing characters to form a string. The
string continues until it is terminated by another @litchar{"} (that
is not escaped by @litchar["\\"]).
Within a string sequence, the following escape sequences are
recognized:
@itemize{
@item{@as-index{@litchar["\\a"]}: alarm (ASCII 7)}
@item{@as-index{@litchar["\\b"]}: backspace (ASCII 8)}
@item{@as-index{@litchar["\\t"]}: tab (ASCII 9)}
@item{@as-index{@litchar["\\n"]}: linefeed (ASCII 10)}
@item{@as-index{@litchar["\\v"]}: vertical tab (ASCII 11)}
@item{@as-index{@litchar["\\f"]}: formfeed (ASCII 12)}
@item{@as-index{@litchar["\\r"]}: return (ASCII 13)}
@item{@as-index{@litchar["\\e"]}: escape (ASCII 27)}
@item{@as-index{@litchar["\\\""]}: double-quotes (without terminating the string)}
@item{@as-index{@litchar["\\'"]}: quote (i.e., the backslash has no effect)}
@item{@as-index{@litchar["\\\\"]}: backslash (i.e., the second is not an escaping backslash)}
@item{@as-index{@litchar["\\"]@kleenerange[1 3]{@nonterm{digit@sub{8}}}}:
Unicode for the octal number specified by @kleenerange[1
3]{digit@sub{8}} (i.e., 1 to 3 @nonterm{digit@sub{8}}s) where
each @nonterm{digit@sub{8}} is @litchar{0}, @litchar{1},
@litchar{2}, @litchar{3}, @litchar{4}, @litchar{5},
@litchar{6}, or @litchar{7}. A longer form takes precedence
over a shorter form, and the resulting octal number must be
between 0 and 255 decimal, otherwise the
@exnraise[exn:fail:read].}
@item{@as-index{@litchar["\\x"]@kleenerange[1
2]{@nonterm{digit@sub{16}}}}: Unicode for the hexadecimal
number specified by @kleenerange[1 2]{@nonterm{digit@sub{16}}},
where each @nonterm{digit@sub{16}} is @litchar{0}, @litchar{1},
@litchar{2}, @litchar{3}, @litchar{4}, @litchar{5},
@litchar{6}, @litchar{7}, @litchar{8}, @litchar{9},
@litchar{a}, @litchar{b}, @litchar{c}, @litchar{d},
@litchar{e}, or @litchar{f} (case-insensitive). The longer form
takes precedence over the shorter form.}
@item{@as-index{@litchar["\\u"]@kleenerange[1
4]{@nonterm{digit@sub{16}}}}: like @litchar["\\x"], but with up
to four hexadecimal digits (longer sequences take precedence).
The resulting hexadecimal number must be a valid argument to
@scheme[integer->char], otherwise the
@exnraise[exn:fail:read].}
@item{@as-index{@litchar["\\U"]@kleenerange[1
8]{@nonterm{digit@sub{16}}}}: like @litchar["\\x"], but with up
to eight hexadecimal digits (longer sequences take precedence).
The resulting hexadecimal number must be a valid argument to
@scheme[integer->char], otherwise the
@exnraise[exn:fail:read].}
@item{@as-index{@litchar["\\"]@nonterm{newline}}: elided, where
@nonterm{newline} is either a linefeed, carriage return, or
carriage return--linefeed combination. This convetion allows
single-line strings to span multiple lines in the source.}
}
If the reader encounteres any other use of a backslashe in a string
constant, the @exnraise[exn:fail:read].
@index['("byte strings" "parsing")]{A} string constant preceded by
@litchar{#} is parsed as a byte-string. (That is, @as-index{@litchar{#"}} starts
a byte-string literal.) See @secref["byte-strings"] for
information on byte strings. Byte string constants support the same
escape sequences as character strings, except @litchar["\\u"] and
@litchar["\\U"].
When the reader encounters @as-index{@litchar{#<<}}, it starts parsing a
@pidefterm{here string}. The characters following @litchar{#<<} until
a newline character define a terminator for the string. The content of
the string includes all characters between the @litchar{#<<} line and
a line whose only content is the specified terminator. More precisely,
the content of the string starts after a newline following
@litchar{#<<}, and it ends before a newline that is followed by the
terminator, where the terminator is itself followed by either a
newline or end-of-file. No escape sequences are recognized between the
starting and terminating lines; all characters are included in the
string (and terminator) literally. A return character is not treated
as a line separator in this context. If no characters appear between
@litchar{#<<} and a newline or end-of-file, or if an end-of-file is
encountered before a terminating line, the @exnraise[exn:fail:read].
@reader-examples[
"\"Apple\""
"\"\\x41pple\""
"\"\\\"Apple\\\"\""
"\"\\\\\""
"#\"Apple\""
]
@subsection[#:tag "parse-quote"]{Reading Quotes}
When the reader enounters @as-index{@litchar{'}}, then it recursively
reads one datum, and it forms a new list containing the symbol
@scheme['quote] and the following datum. This convention is mainly
useful for reading Scheme code, where @scheme['s] can be used as a
shorthand for @scheme[(code:quote s)].
Several other sequences are recognized and transformed in a similar
way. Longer prefixes take precedence over short ones:
@read-quote-table[(list @litchar{'} @scheme[quote])
(list @as-index{@litchar{`}} @scheme[quasiquote])
(list @as-index{@litchar{,}} @scheme[unquote])
(list @as-index{@litchar[",@"]} @scheme[unquote-splicing])
(list @as-index{@litchar{#'}} @scheme[syntax])
(list @as-index{@litchar{#`}} @scheme[quasisyntax])
(list @as-index{@litchar{#,}} @scheme[unsyntax])
(list @as-index{@litchar["#,@"]} @scheme[unsyntax-splicing])]
@reader-examples
[
"'apple"
"`(1 ,(+ 2 3))"
]
@subsection[#:tag "parse-comment"]{Reading Comments}
A @as-index{@litchar{;}} starts a line comment. When the reader
encounters @litchar{;}, then it skips past all characters until the
next linefeed or carriage return.
A @litchar["#|"] starts a nestable block comment. When the reader
encounters @litchar["#|"], then it skips past all characters until a
closing @litchar["|#"]. Pairs of matching @litchar["#|"] and
@litchar["|#"] can be nested.
A @litchar{#;} starts an S-expression comment. Then the reader
encounters @litchar{#;}, it recursively reads one datum, and then
discards the datum (continuing on to the next datum for the read
result).
@reader-examples
[
"; comment"
"#| a |# 1"
"#| #| a |# 1 |# 2"
"#;1 2"
]
@subsection[#:tag "parse-vector"]{Reading Vectors}
When the reader encounters a @litchar{#(}, @litchar{#[}, or
@litchar["#{"], it starts parsing a vector; see @secref["vectors"] for
information on vectors.
The elements of the vector are recursively read until a matching
@litchar{)}, @litchar{]}, or @litchar["}"] is found, just as for
lists (see @secref["parse-pair"]). A delimited @litchar{.} is not
allowed among the vector elements.
An optional vector length can be specified between the @litchar{#} and
@litchar["("], @litchar["["], or @litchar["{"]. The size is specified
using a sequence of decimal digits, and the number of elements
provided for the vector must be no more than the specified size. If
fewer elements are provided, the last provided element is used for the
remaining vector slots; if no elements are provided, then @scheme[0]
is used for all slots.
In @scheme[read-syntax] mode, each recursive read for the vector
elements is also in @scheme[read-syntax] mode, so that the wrapped
vector's elements are also wraped as syntax objects.
@reader-examples
[
"#(1 apple 3)"
"#3(\"apple\" \"banana\")"
"#3()"
]
@subsection[#:tag "parse-hashtable"]{Reading Hash Tables}
A @litchar{#hash} starts an immutable hash-table constant with key
matching based on @scheme[equal?]. The characters after @litchar{hash}
must parse as a list of pairs (see @secref["parse-pair"]) with a
specific use of delimited @litchar{.}: it must appear between the
elements of each pair in the list, and nowhere in the sequence of list
elements. The first element of each pair is used as the key for a
table entry, and the second element of each pair is the associated
value.
A @litchar{#hasheq} starts a hash table like @litchar{#hash}, except
that it constructs a hash table based on @scheme[eq?] instead of
@scheme[equal?].
In either case, the table is constructed by adding each mapping to the
hash table from left to right, so later mappings can hide earlier
mappings if the keys are equivalent.
@reader-examples
[
"#hash()"
"#hasheq()"
"#hash((\"a\" . 5))"
"#hasheq((a . 5) (b . 7))"
"#hasheq((a . 5) (a . 7))"
]
@subsection[#:tag "parse-box"]{Reading Boxes}
When the reader encounters a @litchar{#&}, it starts parsing a box;
see @secref["boxes"] for information on boxes. The content of the box
is determined by recursively reading the next datum.
In @scheme[read-syntax] mode, the recursive read for the box content
is also in @scheme[read-syntax] mode, so that the wrapped box's
content is also wraped as a syntax object.
@reader-examples
[
"#&17"
]
@subsection[#:tag "parse-character"]{Reading Characters}
A @litchar["#\\"] starts a character constant, which has one of the
following forms:
@itemize{
@item{ @litchar["#\\nul"] or @litchar["#\null"]: NUL (ASCII 0)@nonalpha[]}
@item{ @litchar["#\\backspace"]: backspace (ASCII 8)@nonalpha[]}
@item{ @litchar["#\\tab"]: tab (ASCII 9)@nonalpha[]}
@item{ @litchar["#\\newline"] or @litchar["#\\linefeed"]: linefeed (ASCII 10)@nonalpha[]}
@item{ @litchar["#\\vtab"]: vertical tab (ASCII 11)@nonalpha[]}
@item{ @litchar["#\\page"]: page break (ASCII 12)@nonalpha[]}
@item{ @litchar["#\\return"]: carriage return (ASCII 13)@nonalpha[]}
@item{ @litchar["#\\space"]: space (ASCII 32)@nonalpha[]}
@item{ @litchar["#\\rubout"]: delete (ASCII 127)@nonalpha[]}
@item{@litchar["#\\"]@kleenerange[1 3]{@nonterm{digit@sub{8}}}:
Unicode for the octal number specified by @kleenerange[1
3]{@nonterm{digit@sub{8}}}, as in string escapes (see
@secref["parse-string"]).}
@item{@litchar["#\\x"]@kleenerange[1 2]{@nonterm{digit@sub{16}}}:
Unicode for the hexadecimal number specified by @kleenerange[1
2]{@nonterm{digit@sub{16}}}, as in string escapes (see
@secref["parse-string"]).}
@item{@litchar["#\\u"]@kleenerange[1 4]{@nonterm{digit@sub{16}}}:
like @litchar["#\\x"], but with up to four hexadecimal digits.}
@item{@litchar["#\\U"]@kleenerange[1 6]{@nonterm{digit@sub{16}}}:
like @litchar["#\\x"], but with up to six hexadecimal digits.}
@item{@litchar["#\\"]@nonterm{c}: the character @nonterm{c}, as long
as @litchar["#\\"]@nonterm{c} and the characters following it
do not match any of the previous cases, and as long as the
character after @nonterm{c} is not
@schemelink[char-alphabetic?]{alphabetic}.}
}
@reader-examples
[
"#\\newline"
"#\\n"
"#\\u3BB"
"#\\\u3BB"
]
@subsection[#:tag "parse-keyword"]{Reading Keywords}
A @litchar{#:} starts a keyword. The parsing of a keyword after the
@litchar{#:} is the same as for a symbol, including case-folding in
case-insensitive mode, except that the part after @litchar{#:} is
never parsed as a number.
@reader-examples
[
"#:Apple"
"#:1"
]
@subsection[#:tag "parse-regexp"]{Reading Regular Expressions}
A @litchar{#rx} or @litchar{#px} starts a regular expression. The
characters immediately after @litchar{#rx} or @litchar{#px} must parse
as a string or byte string (see @secref["parse-string"]). A
@litchar{#rx} prefix starts a regular expression as would be
constructed by @scheme[regexp], @litchar{#px} as
constructed by @scheme[pregexp], @litchar{#rx#} as
constructed by @scheme[byte-regexp], and @litchar{#px#} as
constructed by @scheme[byte-pregexp].
@reader-examples
[
"#rx\".*\""
"#px\"[\\\\s]*\""
"#rx#\".*\""
"#px#\"[\\\\s]*\""
]
@subsection[#:tag "parse-graph"]{Reading Graph Structure}
A @graph-defn[] tags the following datum for reference via
@graph-ref[], which allows the reader to produce a datum that
have graph structure.
For a specific @graph-tag in a single read result, each @graph-ref[]
reference is replaced by the datum read for the corresponding
@graph-defn[]; the definition @graph-defn[] also produces just the
datum after it. A @graph-defn[] definition can appear at most
once, and a @graph-defn[] definition must appear before a @graph-ref[]
reference appears.
Although a comment parsed via @litchar{#;} discards the datum
afterward, @graph-defn[] definitions in the discarded datum
still can be referenced by other parts of the reader input, as long as
both the comment and the reference are grouped together by some other
form (i.e., some recursive read); a top-level @litchar{#;} comment
neither defines nor uses graph tags for other top-level forms.
@reader-examples
[
"(#1=100 #1# #1#)"
"#0=(1 . #0#)"
]
@subsection[#:tag "parse-reader"]{Reading via an External Reader}
When the reader encounters @litchar{#reader}, then it loads an
external reader procedure and applies it to the current input stream.
The reader recursively reads the next datum after @litchar{#reader},
and passes it to the procedure that is the value of the
@scheme[current-reader-guard] parameter; the result is used as a
module path. The module path is passed to @scheme[dynamic-require]
with either @scheme['read] or @scheme['read-syntax] (depending on
whether the reader is in @scheme[read] or @scheme[read-syntax]
mode).
The resulting procedure should accept the same arguments as
@scheme[read] or @scheme[read-syntax] in the case thar all optional
arguments are provided. The procedure is given the port whose stream
contained @litchar{#reader}, and it should produce a datum result. If
the result is a syntax object in @scheme[read] mode, then it is
converted to a datum using @scheme[syntax-object->datum]; if the
result is not a syntax object in @scheme[read-syntax] mode, then it is
converted to one using @scheme[datum->syntax-object]. See also
@secref["special-comments"] and @secref["recursive-reads"] for
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].

View File

@ -0,0 +1,462 @@
#|
%
\begin{itemize}
\item Square brackets (``['' and ``]'') and curly braces
(``\{'' and ``\}'') can be used in place of parentheses. An open
square bracket must be closed by a closing square bracket and an open
curly brace must be closed by a closing curly brace. Whether square
brackets are treated as parentheses is controlled by the
\scmfirst{read-square-bracket-as-paren} parameter (see
\SecRef{p:read-square-bracket-as-paren}). Similarly, the parsing of
curly braces is controlled with the
\scmfirst{read-curly-brace-as-paren} parameter. When square brackets
and curly braces are not treated as parentheses, they are disallowed
as input. By default, square brackets and curly braces are treated as
parentheses.
\index{vectors}
\item Vector constants can be unquoted, and a vector size can
be specified with a decimal integer between the \scheme{#} and opening
parenthesis. If the specified size is larger than the number of
vector elements that are provided, the last specified element is used
to fill the remaining vector slots. For example, \scheme{#4(1 2)} is
equivalent to \scheme{#(1 2 2 2)}. If no vector elements are specified,
the vector is filled with \scheme{0}. If a vector size is provided and
it is smaller than the number of elements provided, the
\exnraise{exn:fail:read}.
\index{boxes} {\boxindex}
%
\item Boxed constants can be created using \scheme{#&}. The datum
following \scheme{#&} is treated as a quoted constant and put into
the new box. (Space and comments following the \scheme{#&} are
ignored.) Box reading is controlled with the
\scmfirst{read-accept-box} boolean parameter (see
\SecRef{p:read-accept-box}). Box reading is enabled by default. When
box reading is disabled and \scheme{#&} is provided as input, the
\exnraise{exn:fail:read}.
\scmindex{\#'}\scmindex{\#`}\scmindex{\#,}\scmindex{\#,\atsign}
\item Expressions beginning with \scheme{#'} are wrapped with \scheme{syntax}
in the same way that expressions starting with \scheme{'} are wrapped
with \scheme{quote}. Similarly, \scheme{#`} generates
\scheme{quasisyntax}, \scheme{#,} generates \scheme{unsyntax}, and
\scheme{#,@} generates \scheme{unsyntax-splicing}. See also
\SecRef{quasisyntax}.
\index{characters!constants}
%
\item The following character constants are recognized:
%
\begin{itemize}
\item \scheme{#\nul} or \scheme{#\null} (ASCII 0) \scmchidx{nul} \scmchidx{null}
\item \scheme{#\backspace} (ASCII 8) \scmchidx{backspace}
\item \scheme{#\tab} (ASCII 9) \scmchidx{tab}
\item \scheme{#\newline} or \scheme{#\linefeed} (ASCII 10) \scmchidx{newline}\scmchidx{linefeed}
\item \scheme{#\vtab} (ASCII 11) \scmchidx{vtab}
\item \scheme{#\page} (ASCII 12) \scmchidx{page}
\item \scheme{#\return} (ASCII 13) \scmchidx{return}
\item \scheme{#\space} (ASCII 32) \scmchidx{space}
\item \scheme{#\rubout} (ASCII 127) \scmchidx{rubout}
\end{itemize}
%
Whenever \scheme{#\ } is followed by at least two alphabetic characters,
characters are read from the input port until the next non-alphabetic
character is returned. If the resulting string of letters does not
match one of the above constants (case-insensitively), the
\exnraise{exn:fail:read}.
Character constants can also be specified through direct Unicode values
in octal notation (up to 255): \rawscm{\#{\TTBackslash}\var{n$_1$}\var{n$_2$}\var{n$_3$}} where
\var{n$_1$} is in the range [\scheme{0}, \scheme{3}] and \var{n$_2$} and
\var{n$_3$} are in the range [\scheme{0}, \scheme{7}]. Whenever \scheme{#\ } is
followed by at least two characters in the range [\scheme{0}, \scheme{7}],
the next character must also be in this range, and the resulting octal
number must be in the range $000_8$ to $377_8$.
Finally, character constants can be specified through direct Unicode
values in hexadecimal notation:
\rawscm{\#{\TTBackslash}u\var{n$_1$}...\var{n$_k$}}
or \rawscm{\#{\TTBackslash}U\var{n$_1$}...\var{n$_k$}}, where each
\var{n$_i$} is a hexadecimal digit (0-9, a-f, or A-F), and $k$ is no
more than $4$ for \rawscm{\#{\TTBackslash}u} or $6$ for \rawscm{\#{\TTBackslash}U}.
Whenever \scheme{#\ } is followed by a \scheme{u} or \scheme{U} and
one hexadecimal digit, the character constant is terminated by either
the first non-hexadecimal character in the stream, or the fourth/sixth
hexadecimal character, whichever comes first. The resulting
hexadecimal number must be a valid argument to
\rawscm{integer->char}, otherwise the \exnraise{exn:fail:read}.
Unless otherwise specified above, character-constants are terminated
after the character following \scheme{#\ }. For example, if
\scheme{#\ } is followed by an alphabetic character other than
\rawscm{u} and then a non-alphabetic character, then the character
constant is terminated. If \scheme{#\ } is followed by a \scheme{8}
or \scheme{9}, then the constant is terminated. If \scheme{#\ } is
followed by a non-alphabetic, non-decimal-digit character then the
constant is terminated.
\index{strings}
%
\item Within string constants, the following escape sequences are
recognized in addition to \stresc{"} and \stresc{{\TTBackslash}}:
%
\begin{itemize}
\item \istresc{a}: alarm (ASCII 7)
\item \istresc{b}: backspace (ASCII 8)
\item \istresc{t}: tab (ASCII 9)
\item \istresc{n}: linefeed (ASCII 10)
\item \istresc{v}: vertical tab (ASCII 11)
\item \istresc{f}: formfeed (ASCII 12)
\item \istresc{r}: return (ASCII 13)
\item \istresc{e}: escape (ASCII 27)
\item \istresc{'}: quote (i.e., the backslash has no effect)
\item \iistresc{o}{\var{o}}, \iistresc{oo}{\var{oo}}, or \iistresc{oo}{\var{ooo}}:
Unicode for octal \var{o}, \var{oo}, or \var{ooo}, where each
\var{o} is \rawscm{0}, \rawscm{1}, \rawscm{2}, \rawscm{3}, \rawscm{4},
\rawscm{5}, \rawscm{6}, or \rawscm{7}. The \stresc{\var{ooo}} form
takes precedence over the \stresc{\var{oo}} form, and
\stresc{\var{oo}} takes precedence over \stresc{\var{o}}.
\item \iistresc{xh}{x\var{h}} or \iistresc{xh}{x\var{hh}}: Unicode for hexadecimal
\var{h} or \var{hh}, where each \var{h} is \rawscm{0}, \rawscm{1},
\rawscm{2}, \rawscm{3}, \rawscm{4}, \rawscm{5}, \rawscm{6}, \rawscm{7}, \rawscm{a},
\rawscm{A}, \rawscm{b}, \rawscm{B}, \rawscm{c}, \rawscm{C}, \rawscm{d}, \rawscm{D},
\rawscm{e}, \rawscm{E}, \rawscm{f}, or \rawscm{F}. The \stresc{x\var{hh}}
form takes precedence over the \stresc{x\var{h}} form.
\item \iistresc{uh}{u\var{h}}, \iistresc{uhh}{u\var{hh}},
\iistresc{uhhh}{u\var{hhh}}, or \iistresc{uhhhh}{u\var{hhhh}}:
like \stresc{x}, but with up to four hexadecimal digits (longer
sequences take precedence). The resulting hexadecimal number
must be a valid argument to \rawscm{integer->char}, otherwise
the \exnraise{exn:fail:read}.
\item \iistresc{Uh}{U\var{h}}, \iistresc{Uhh}{U\var{hh}}, \iistresc{Uhhh}{U\var{hhh}},
\iistresc{Uhhhh}{U\var{hhhh}}, \iistresc{Uhhhhh}{U\var{hhhhh}}, \iistresc{Uhhhhhh}{U\var{hhhhhh}},
\iistresc{Uhhhhhhh}{U\var{hhhhhhh}}, or \iistresc{Uhhhhhhhh}{U\var{hhhhhhhh}}:
like \stresc{x}, but with up to eight hexadecimal digits (longer
sequences take precedence). The resulting hexadecimal number
must be a valid argument to \rawscm{integer->char}, otherwise
the \exnraise{exn:fail:read}.
\end{itemize}
%
Furthermore, a backslash followed by a linefeed, carriage return or
return-linefeed combination is elided, allowing string constants to
span lines. Any other use of backslash within a string constant is an
error.
%
\scmindex{\#""}
\index{byte strings}
%
\item A string constant preceded by \scheme{#} is a byte-string
constant. Byte string constants support the same escape sequences as
character strings except \stresc{u} and \stresc{U}.
\index{here strings}\scmindex{\#<<}
%
\item The sequence \scheme{#<<} starts a \pidefterm{here string}. The
characters following \scheme{#<<} until a newline character define a
terminator for the string. The content of the string includes all
characters between the \scheme{#<<} line and a line whose only
content is the specified terminator. More precisely, the content of
the string starts after a newline following \scheme{#<<}, and it ends
before a newline that is followed by the terminator, where the
terminator is itself followed by either a newline or end-of-file. No
escape sequences are recognized between the starting and terminating
lines; all characters are included in the string (and terminator)
literally. A return character is not treated as a line separator in
this context. If no characters appear between \scheme{#<<} and a
newline or end-of-file, or if an end-of-file is encountered before a
terminating line, the \exnraise{exn:fail:read}.
\index{numbers} %
%
\item The syntax for numbers is extended as described in
\SecRef{numbers}. Numbers containing a decimal point or exponent
(e.g., \scheme{1.3}, \scheme{2e78}) are normally read as inexact. If
the \scmfirst{read-decimal-as-inexact} parameter is set to
\scheme{#f}, then such numbers are instead read as exact. The
parameter does not affect the parsing of numbers with an explicit
exactness tag (\scheme{#e} or \scheme{#i}).
\label{mz:infix}
\index{infix} %
%
\item A parenthesized sequence containing two delimited dots
(``\scheme{.}'') triggers infix parsing. A single \var{datum} must
appear between the dots, and one or more \var{datum}s must appear
before the first dot and after the last dot:
%
\begin{center}
\begin{schemebox}
(left-datum \xdots . first-datum . right-datum \xdots)
\end{schemebox}
\end{center}
%
The resulting list consists of the \var{datum} between the dots,
followed by the remaining \var{datum}s in order:
%
\begin{center}
\begin{schemebox}
(first-datum left-datum \xdots right-datum \xdots)
\end{schemebox}
\end{center}
%
Consequently, the input expression \scheme{(1 . < . 2)} produces
\scheme{#t}, and \scheme{(1 2 . + . 3 4 5)} produces \scheme{15}.
\index{.}\index{`}\index{",}\index{","@}
%
\item When the \scmfirst{read-accept-dot} parameter is set to
\scheme{#f}, then a delimited dot (``\scheme{.}'') is disallowed in
input. When the \scmfirst{read-accept-quasiquote} parameter is set to
\scheme{#f}, then a backquote or comma is disallowed in input. These
modes simplify Scheme's input model for students.
\index{symbols} \scmindex{|} \index{{\Backslash}}
%
\item MzScheme's identifier and symbol syntax is considerably more
liberal than the syntax specified by {\rfivers}. When input is
scanned for tokens, the following characters delimit an identifier in
addition to whitespace:
\scmline{" , ' ` ; ( ) [ ] \{ \}}
In addition, an identifier cannot start with a hash mark
(``\scheme{#}'') unless the hash mark is immediately followed by a
percent sign (``\scheme{%}''). The only other
special characters are backslash (``{\Backslash}'') and quoting
vertical bars (``$|$''); any other character is used as part of an
identifier.
Symbols containing special characters (including delimiters) are
expressed using an escaping backslash (``{\Backslash}'') or quoting
vertical bars (``$|$''):
%
\begin{itemize}
\item A backslash preceding any character includes that character in
the symbol literally; double backslashes produce a single backslash
in the symbol.
\item Characters between a pair of vertical bars are included in the
symbol literally. Quoting bars can be used for any part of a symbol,
or the whole symbol can be quoted. Backslashes and quoting bars can
be mixed within a symbol, but a backslash is \Em{not} a special
character within a pair of quoting bars.
\end{itemize}
%
Characters quoted with a backslash or a vertical bar always preserve
their case, even when identifiers are read case-insensitively.
An input token constructed in this way is an identifier when it is not
a numerical constant (following the extended number syntax described
in \SecRef{numbers}). A token containing a backslash or vertical bars
is never treated as a numerical constant.
Examples:
%
\begin{itemize}
\item \rawscm{(\scmk{quote} a{\TTBackslash}(b)} produces the same symbol as
\scheme{(string->symbol "a(b")}.
\item \rawscm{(\scmk{quote} A{\TTBackslash}B)} produces the same
symbol as \scheme{(string->symbol "aB")} when identifiers are read
without case-sensitivity.
\item \rawscm{(\scmk{quote} a{\TTBackslash} b)}, \rawscm{(\scmk{quote} $|$a b$|$)}, and
\rawscm{(\scmk{quote} a$|$ $|$b)} all produce the same symbol as
\scheme{(string->symbol "a b")}.
\item \rawscm{(\scmk{quote} $|$a$||$b$|$)} is the same as \rawscm{(\scmk{quote} $|$ab$|$)},
which produces the same symbol as \scheme{(string->symbol "ab")}.
\item \rawscm{(\scmk{quote} 10)} is the number 10, but \rawscm{(\scmk{quote} $|$10$|$)}
produces the same symbol as \scheme{(string->symbol "10")}.
\end{itemize}
Whether a vertical bar is used as a special or normal symbol character
is controlled with the \scmfirst{read-accept-bar-quote} boolean
parameter (see \SecRef{p:read-accept-bar-quote}). Vertical bar quotes
are enabled by default. Quoting backslashes cannot be disabled.
\index{symbols!case sensitivity}
%
\item By default, symbols are read case-sensitively. Case
sensitivity for reading can be controlled in three ways:
\begin{itemize}
\item Quoting part of a symbol with an escaping backslash
(``{\Backslash}'') or quoting vertical bar (``$|$'') always
preserves the case of the quoted portion, as described above.
\item \scmindex{\#cs} \scmindex{\#ci} The sequence \rawscm{\#cs} can
be used as a prefix for any expression to make reading symbols
within the expression case-sensitive. A \rawscm{\#ci} prefix
similarly makes reading symbols in an expression case-insensitive.
Whitespace can appear between a \rawscm{\#cs} or \rawscm{\#ci}
prefix and its expression, and prefixes can be nested. Backslash and
vertical-bar quotes override a \rawscm{\#ci} prefix.
\item When the \scmfirst{read-case-sensitive} parameter (see
\SecRef{p:read-case-sensitive}) is set to \scheme{#t}, then case is
preserved when reading symbols. The default is \scheme{#t}, and it
is set to \scheme{#t} while loading a module (see
\SecRef{modloadhandler}). A \rawscm{\#cs} or \rawscm{\#ci} prefix
overrides the parameter setting, as does backslash or vertical-bar
quoting.
\end{itemize}
%
Symbol case conversions are \emph{not} sensitive to the current locale
(see \SecRef{locales}).
\index{keywords} \scmindex{:} \scmindex{\#k+} \scmindex{\#k-}
%
\item A symbol-like expression that starts with an unquoted hash and
colon (``\#:'') is parsed as a keyword constant. After the leading
colon, backslashes, vertical bars, and case sensitivity are handled
as for symbols, except that a keyword expression can never be
interpreted as a number.
\index{regular expressions!constants}
\scmindex{\#rx}
\scmindex{\#rx\#}
%
\item Expressions of the form \rawscm{\#rx\var{string}} are literal
regexp values (see \SecRef{regexp}) where \var{string} is a string
constant. The regexp produced by \rawscm{\#rx\var{string}} is the
same as produced by \rawscm{(regexp \var{string})}. If \var{string}
is not a valid pattern, the \exnraise{exn:fail:read}.
Expressions of the form \rawscm{\#rx\#\var{string}} are similarly literal
byte-regexp values. The regexp produced by \rawscm{\#rx\#\var{string}} is the
same as produced by \rawscm{(byte-regexp \#\var{string})}.
\index{regular expressions!constants}
\scmindex{\#px}
\scmindex{\#px\#}
%
\item Expressions of the form \rawscm{\#px\var{string}} and
\rawscm{\#px\#\var{string}} are like the \rawscm{\#rx} variants,
except that the regexp is as produced by \rawscm{pregexp} and
\rawscm{byte-pregexp} (see \SecRef{regexp}) instead of
\rawscm{regexp} and \rawscm{byte-regexp}.
\index{hash tables!constants}
\scmindex{\#hash}
\scmindex{\#hasheq}
%
\item Expressions of the form \rawscm{\#hash((\var{key-datum}
. \var{val-datum}) \odots)} are literal immutable hash tables. The
hash table maps each \var{key-datum} to its \var{val-datum},
comparing keys with \scheme{equal?}. The table is constructed by
adding each \var{key-datum} mapping from left to right, so later
mappings can hide earlier mappings if the \var{key-datum}s are
\scheme{equal?}. An expression of the form
\rawscm{\#hasheq((\var{key-datum} . \var{val-datum}) \odots)}
produces an immutable hash table with keys compared using
\scheme{eq?}. If the value of \scmfirst{read-square-bracket-as-paren}
parameter (see \SecRef{p:read-square-bracket-as-paren}) is true,
matching parentheses in a \rawscm{\#hash} or \rawscm{\#hasheq}
constant can be replaced by matching square brackets. Similarly,
matching curly braces can be used if
\scmfirst{read-curly-brace-as-paren} is true.
\index{graphs} \scmindex{\#\var{n}=} \scmindex{\#\var{n}\#}
%
\item Values with shared structure are expressed using
\rawscm{\#\var{n}=} and \rawscm{\#\var{n}\#}, where \var{n} is
a decimal integer. See \SecRef{sexpressions}.
\scmindex{\#\%}
%
\item Expressions of the form \rawscm{\#\%\var{x}} are symbols, where
\var{x} can be a symbol or a number.
\scmindex{\#{\Tilde}}
%
\item Expressions beginning with \scheme{#~} are interpreted as
compiled MzScheme code. See \SecRef{compilation}.
\index{comments}
%
\item Multi-line comments are started with \rawscm{\#{\tt |}} and terminated
with \rawscm{{\tt |}\#}. Comments of this form can be nested arbitrarily.
\scmindex{comments!S-expression}
\scmindex{\#;}
%
\item A \rawscm{\#;} comments out the next datum. Whitespace and
comments (including \rawscm{\#;} comments) may appear between the
\rawscm{\#;} and the commented-out datum. Graph-structure annotations
with \rawscm{\#\var{n}=} and \rawscm{\#\var{n}\#} work within the
comment as if the datum were not commented out (e.g., bindings can be
introduced with \rawscm{\#\var{n}=} for use in parts of the datum
that are not commented out). When \rawscm{\#;} appears at the
beginning of a top-level datum, however, graph-structure bindings are
discarded (along with the first following datum) before reading the
second following datum.
\scmindex{load}
\scmindex{\#"!}
%
\item If the first line of a \scheme{load}ed file begins with
\scheme{#!}, it is ignored by the default load handler. If an ignored
line ends with a backslash (``{\Backslash}''), then the next line is
also ignored. (The \scheme{#!} convention is for shell scripts; see
\ChapRef{scripts} for details.)
\scmindex{\#hx} \scmindex{\#sx}
%
\item A \rawscm{\#hx} shifts the reader into H-expression mode (see
\SecRef{honu}) for one H-expression. A \rawscm{\#sx} has no effect in
normal mode, but in H-expression mode, it shifts the reader back to
(normal) S-expression mode. The \rawscm{read-honu} and
\rawscm{read-honu-syntax} procedures read as if the stream starts
with \rawscm{\#hx}.
\scmindex{\#honu}
%
\item A \rawscm{\#honu} shifts the reader into H-expression mode (see
\SecRef{honu}) and reads repeatedly until an end-of-file is
encountered. The H-expression results are wrapped in a module-formed
S-expression, as described in \SecRef{honu}.
\scmindex{\#reader}
%
\item A \rawscm{\#reader} must be followed by a datum. The datum is
passed to the procedure that is the value of the
\rawscm{current-reader-guard} parameter (see
\SecRef{p:current-reader-guard}), and the result is used as a module
path. The module path is passed to \rawscm{dynamic-require} (see
\SecRef{dynreq}) with either \Symbol{read} or \Symbol{read-syntax}
(depending on whether parsing started with \rawscm{read} or
\rawscm{read-syntax}). The resulting procedure should accept the same
arguments as \rawscm{read} or \rawscm{read-syntax} (with all optional
arguments as required). The procedure is given the port whose stream
contained \rawscm{\#reader}, and it should produce a datum result. If
the result is a syntax object in \rawscm{read} mode it is converted
to a datum using \rawscm{syntax-object->datum}; if the result is not
a syntax object in \rawscm{read-syntax} mode, it is converted to one
using \rawscm{datum->syntax-object}. See also
\SecRef{special-comments} and \SecRef{recursive-reads} for
information on special-comment results and recursive reads. If the
\rawscm{read-accept-reader} parameter is set to \scheme{#f}, then
\rawscm{\#reader} is disallowed as input.
|#

View File

@ -0,0 +1,142 @@
(module reader-example mzscheme
(require (lib "struct.ss" "scribble")
(lib "decode.ss" "scribble")
(lib "manual.ss" "scribble")
(lib "scheme.ss" "scribble")
(lib "kw.ss")
(lib "class.ss"))
(provide reader-examples
read-quote-table
dispatch-table
dispatch
metavar
cilitchar)
(define (as-flow i) (make-flow (list (make-paragraph (if (list? i)
i
(list i))))))
(define spacer (hspace 1))
(define (reader-examples . strs)
(make-table
#f
(cons
(list (as-flow "Examples:")
(as-flow "")
(as-flow ""))
(map (lambda (s)
(list (as-flow (list spacer
(litchar s)))
(as-flow (list spacer
"reads equal to"
spacer))
(as-flow (let ([v (read (open-input-string s))])
(cond
[(eof-object? v)
(make-element 'italic '("nothing"))]
[(string? v)
(make-element "schemevalue"
(list (schemefont
(regexp-replace* #rx"[\\]\""
(regexp-replace*
#rx"[\\][\\]"
(format "~s" v)
"\\\\x5C")
"\\\\x22"))))]
[else
(let ([e (let loop ([v v])
(cond
[(memq v '(quasiquote unquote +)) `',v]
[(symbol? v) `(string->symbol ,(format "~a" v))]
[(number? v)
(let loop ([v v])
(if (inexact? v)
`(inexact->exact ,(loop (inexact->exact v)))
(cond
[(integer? v) v]
[(real? v) `(/ ,(numerator v)
,(denominator v))]
[(complex? v) `(make-complex ,(loop (real-part v))
,(loop (imag-part v)))])))]
[(list? v) `(list ,@(map loop v))]
[(vector? v) `(vector ,@(map loop (vector->list v)))]
[(box? v) `(box ,(loop (unbox v)))]
[(and (pair? v)
(eq? v (cdr v))
(eq? 1 (car v)))
#`(let ([v (cons 1 #f)]) (set-cdr! v v) v)]
[(pair? v) `(cons ,(loop (car v)) ,(loop (cdr v)))]
[(bytes? v) `(bytes ,@(map loop (bytes->list v)))]
[(char? v) `(integer->char ,(char->integer v))]
[(keyword? v) `(string->keyword ,(format "~a" v))]
[(or (regexp? v)
(byte-regexp? v))
`(,(cond
[(pregexp? v) 'pregexp]
[(byte-pregexp? v) 'byte-pregexp]
[(byte-regexp? v) 'byte-regexp]
[else 'regexp])
,(object-name v))]
[(hash-table? v)
`(make-immutable-hash-table (quote ,(hash-table-map v cons))
,@(if (hash-table? v 'equal)
'('equal)
'()))]
[else v]))])
(to-element (syntax-ize e 0)))])))))
strs))))
(define (read-quote-table . l)
(make-table
#f
(map (lambda (p)
(list (as-flow spacer)
(as-flow (car p))
(as-flow (list spacer "adds" spacer))
(as-flow (cadr p))))
l)))
(define (dispatch-table . l)
(make-table
'((alignment . (left right left left)))
(map (lambda (p)
(list (as-flow spacer)
(as-flow (car p))
(as-flow spacer)
(as-flow (cadr p))))
l)))
(define (dispatch a . b)
(list a (make-element #f (decode-content b))))
(define/kw (metavar #:body s)
(make-element 'italic (decode-content s)))
(define (cilitchar s)
(let ([ss (map list->string
(let loop ([l (string->list s)])
(if (null? l)
(list null)
(let ([r (loop (cdr l))])
(if (char-alphabetic? (car l))
(append
(map (lambda (i) (cons (char-downcase (car l)) i)) r)
(map (lambda (i) (cons (char-upcase (car l)) i)) r))
(map (lambda (i) (cons (car l) i)) r))))))])
(case (length ss)
[(1) (litchar (car ss))]
[(2) (make-element #f (list (litchar (car ss)) " or "
(litchar (cadr ss))))]
[else
(make-element #f
(let loop ([ss ss])
(if (null? (cdr ss))
(list " or " (litchar (car ss)))
(list* (litchar (car ss))
", "
(loop (cdr ss))))))]))))

View File

@ -0,0 +1,11 @@
#reader(lib "docreader.ss" "scribble")
@require["mz.ss"]
@title{PLT Scheme Reference Manual}
@table-of-contents[]
@include-section["read.scrbl"]
@include-section["data.scrbl"]
@index-section["mzscheme-index"]

View File

@ -0,0 +1,341 @@
#reader(lib "docreader.ss" "scribble")
@require["mz.ss"]
@title[#:tag "strings"]{Strings}
A @pidefterm{string} is a fixed-length arary of
@seclink["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
immutable.
Two strings are @scheme[eq?] when mutating one would mutate the other.
Two strings are @scheme[eqv?] and @scheme[equal?] when they have the
same length and contain the same sequence of characters.
See also: @scheme[immutable], @scheme[symbol->string],
@scheme[bytes->string/utf-8].
@; ----------------------------------------
@section{String Constructors, Selectors, and Mutators}
@defproc[(make-string [k exact-nonnegative-integer?] [char char?
#\nul]) string?]{ Returns a new mutable string of length @scheme[k] where
each position in the string is initialized with the character
@scheme[char].
@examples[(make-string 5 #\z)]}
@defproc[(string [char char?] ...0) string?]{ Returns a new
mutable string whose length is the number of provided @scheme[char]s, and
whose positions are initialized with the given @scheme[char]s.
@examples[(string #\A #\p #\p #\l #\e)]}
@defproc[(string->immutable-string [str string?]) (and/c string?
immutable?)]{ Returns an immutable string with the same content as
@scheme[str], returning @scheme[str] itself if @scheme[str] is
immutable.}
@defproc[(string? [v any/c]) boolean?]{ Returns @scheme[#t] if @scheme[v]
is a string, @scheme[#f] otherwise.
@examples[(string? "Apple") (string? 'apple)]}
@defproc[(string-length [str string?]) exact-nonnegative-integer?]{
Returns the length of @scheme[str].
@examples[(string-length "Apple")]}
@defproc[(string-ref [str string?] [k exact-nonnegative-integer?])
char?]{ Returns the character at position @scheme[k] in @scheme[str].
The first position in the string cooresponds to @scheme[0], so the
position @scheme[k] must be less than the length of the string,
otherwise the @exnraise[exn:fail:contract].
@examples[(string-ref "Apple" 0)]}
@defproc[(string-set! [str (and/c string? (not/c immutable?))] [k
exact-nonnegative-integer?] [char char?]) void?]{ Changes the
character position @scheme[k] in @scheme[str] to @scheme[char]. The first
position in the string cooresponds to @scheme[0], so the position
@scheme[k] must be less than the length of the string, otherwise the
@exnraise[exn:fail:contract].
@examples[(define s (string #\A #\p #\p #\l #\e))
(string-set! s 4 #\y)
s]}
@defproc[(substring [str string?] [start exact-nonnegative-integer?]
[end exact-nonnegative-integer? (string-length str)]) string?]{
Returns a new mutable string that is @scheme[(- @scheme[end]
@scheme[start])] characters long, and that contains the same characters
as @scheme[str] from @scheme[start] inclusive to @scheme[end] exclusive. The
@scheme[start] and @scheme[end] arguments must be less than the length of
@scheme[str], and @scheme[end] must be greater than or equal to @scheme[str],
otherwise the @exnraise[exn:fail:contract].
@examples[(substring "Apple" 1 3)
(substring "Apple" 1)]}
@defproc[(string-copy [str string?]) string?]{ Returns
@scheme[(substring str 0)].}
@defproc[(string-copy! [dest (and/c string? (not/c immutable?))]
[dest-start exact-nonnegative-integer?]
[src string?]
[src-start exact-nonnegative-integer? 0]
[src-end exact-nonnegative-integer? (string-length src)])
void?]{
Changes the characters of @scheme[dest] from positions
@scheme[dest-start] (inclusive) to @scheme[dest-end] (exclusive) to
match the characters in @scheme[src] from @scheme[src-start]
(inclusive). The strings @scheme[dest] and @scheme[src] can be the
same string, and in that case the destination region can overlap with
the source region; the destination characters after the copy match
the source characters from before the copy. If any of
@scheme[dest-start], @scheme[src-start], or @scheme[src-end]
are out of range (taking into account the sizes of the strings and
the source and destination regions), the
@exnraise[exn:fail:contract].
@examples[(define s (string #\A #\p #\p #\l #\e))
(string-copy! s 4 "y")
(string-copy! s 0 s 3 4)
s]}
@defproc[(string-fill! [dest (and/c string? (not/c immutable?))] [char
char?]) void?]{ Changes @scheme[dest] so that every position in the
string is filled with @scheme[char].
@examples[(define s (string #\A #\p #\p #\l #\e))
(string-fill! s #\q)
s]}
@defproc[(string-append [str string?] ...0) string?]{ Returns a new
mutable string that is as long as the sum of the given @scheme[str]s'
lengths, and that contains the concatenated characters of the given
@scheme[str]s. If no @scheme[str]s are provided, the result is a zero-length
string.
@examples[(string-append "Apple" "Banana")]}
@defproc[(string->list [str string?]) (listof char?)]{ Returns a new
list of characters coresponding to the content of @scheme[str]. That is,
the length of the list is @scheme[(string-length @scheme[str])], and the
sequence of characters of @scheme[str] are in the same sequence in the
result list.
@examples[(string->list "Apple")]}
@defproc[(list->string [lst (listof char?)]) string?]{ Returns a new
mutable string whose content is the list of characters in @scheme[lst].
That is, the length of the string is @scheme[(length @scheme[lst])], and
the sequence of characters in @scheme[lst] is in the same sequence in
the result string.
@examples[(list->string (list #\A #\p #\p #\l #\e))]}
@; ----------------------------------------
@section{String Comparisons}
@defproc[(string=? [str1 string?] [str2 string?] ...1) boolean?]{ Returns
@scheme[#t] if all of the arguments are @scheme[eqv?].}
@examples[(string=? "Apple" "apple")
(string=? "a" "as" "a")]
@define[(string-sort direction folded?)
(if folded?
@elem{Like @scheme[string-ci<?], but checks whether the arguments would be @direction after case-folding.}
@elem{Like @scheme[string<?], but checks whether the arguments are @|direction|.})]
@defproc[(string<? [str1 string?] [str2 string?] ...1) boolean?]{
Returns @scheme[#t] if the arguments are lexicographically sorted
increasing, where individual characters are ordered by
@scheme[char<?], @scheme[#f] otherwise.
@examples[(string<? "Apple" "apple")
(string<? "apple" "Apple")
(string<? "a" "b" "c")]}
@defproc[(string<=? [str1 string?] [str2 string?] ...1) boolean?]{
@string-sort["nondecreasing" #f]
@examples[(string<=? "Apple" "apple")
(string<=? "apple" "Apple")
(string<=? "a" "b" "b")]}
@defproc[(string>? [str1 string?] [str2 string?] ...1) boolean?]{
@string-sort["decreasing" #f]
@examples[(string>? "Apple" "apple")
(string>? "apple" "Apple")
(string>? "c" "b" "a")]}
@defproc[(string>=? [str1 string?] [str2 string?] ...1) boolean?]{
@string-sort["nonincreasing" #f]
@examples[(string>=? "Apple" "apple")
(string>=? "apple" "Apple")
(string>=? "c" "b" "b")]}
@defproc[(string-ci=? [str1 string?] [str2 string?] ...1) boolean?]{
Returns @scheme[#t] if all of the arguments are @scheme[eqv?] after
locale-insensitive case-folding via @scheme[string-foldcase].
@examples[(string-ci=? "Apple" "apple")
(string-ci=? "a" "a" "a")]}
@defproc[(string-ci<? [str1 string?] [str2 string?] ...1) boolean?]{
Like @scheme[string<?], but checks whether the arguments would be in
increasing order if each was first case-folded using
@scheme[string-foldcase] (which is locale-insensitive).
@examples[(string-ci<? "Apple" "apple")
(string-ci<? "apple" "banana")
(string-ci<? "a" "b" "c")]}
@defproc[(string-ci<=? [str1 string?] [str2 string?] ...1) boolean?]{
@string-sort["nondecreasing" #t]
@examples[(string-ci<=? "Apple" "apple")
(string-ci<=? "apple" "Apple")
(string-ci<=? "a" "b" "b")]}
@defproc[(string-ci>? [str1 string?] [str2 string?] ...1) boolean?]{
@string-sort["decreasing" #t]
@examples[(string-ci>? "Apple" "apple")
(string-ci>? "banana" "Apple")
(string-ci>? "c" "b" "a")]}
@defproc[(string-ci>=? [str1 string?] [str2 string?] ...1) boolean?]{
@string-sort["nonincreasing" #t]
@examples[(string-ci>=? "Apple" "apple")
(string-ci>=? "apple" "Apple")
(string-ci>=? "c" "b" "b")]}
@; ----------------------------------------
@section{String Conversions}
@defproc[(string-upcase [str string?]) string?]{ Returns a string
whose characters are the upcase conversion of the characters in
@scheme[str]. The conversion uses Unicode's locale-independent
conversion rules that map code-point sequences to code-point
sequences (instead of simply mapping a 1-to-1 function on code points
over the string), so the string produced by the conversion can be
longer than the input string.
@examples[
(string-upcase "abc!")
(string-upcase "Stra\xDFe")
]}
@defproc[(string-downcase [string string?]) string?]{ Like
@scheme[string-upcase], but the downcase conversion.
@examples[
(string-downcase "aBC!")
(string-downcase "Stra\xDFe")
(string-downcase "\u039A\u0391\u039F\u03A3")
(string-downcase "\u03A3")
]}
@defproc[(string-titlecase [string string?]) string?]{ Like
@scheme[string-upcase], but the titlecase conversion only for the
first character in each sequence of cased characters in @scheme[str]
(ignoring case-ignorable characters).
@examples[
(string-titlecase "aBC twO")
(string-titlecase "y2k")
(string-titlecase "main stra\xDFe")
(string-titlecase "stra \xDFe")
]}
@defproc[(string-foldcase [string string?]) string?]{ Like
@scheme[string-upcase], but the case-folding conversion.
@examples[
(string-foldcase "aBC!")
(string-foldcase "Stra\xDFe")
(string-foldcase "\u039A\u0391\u039F\u03A3")
]}
@defproc[(string-normalize-nfd [string string?]) string?]{ Returns a
string that is the Unicode normalized form D of @scheme[string]. If
the given string is already in the corresponding Unicode normal form,
the string may be returned directly as the result (instead of a newly
allocated string).}
@defproc[(string-normalize-nfkd [string string?]) string?]{ Like
@scheme[string-normalize-nfd], but for normalized form KD.}
@defproc[(string-normalize-nfc [string string?]) string?]{ Like
@scheme[string-normalize-nfd], but for normalized form C.}
@defproc[(string-normalize-nfkc [string string?]) string?]{ Like
@scheme[string-normalize-nfd], but for normalized form KC.}
@; ----------------------------------------
@section{Locale-Specific String Operations}
@defproc[(string-locale=? [str1 string?] [str2 string?] ...1)
boolean?]{ Like @scheme[string=?], but the strings are compared in a
locale-specific way, based the value of @scheme[current-locale]. See
@secref["locales"] for more information on locales.}
@defproc[(string-locale<? [str1 string?] [str2 string?] ...1) boolean?]{
Like @scheme[string<?], but the sort order compares strings in a
locale-specific way, based the value of @scheme[current-locale]. In
particular, the sort order may not be simply a lexicographic
extension of character ordering.}
@defproc[(string-locale>? [str1 string?] [str2 string?] ...1)
boolean?]{ Like @scheme[string>?], but locale-specific like
@scheme[string-locale<?].}
@defproc[(string-locale-ci=? [str1 string?] [str2 string?] ...1)
boolean?]{ Like @scheme[string-locale=?], but strings are compared
using rules that are both locale-specific and case-insensitive
(depending on what ``case-insensitive'' means for the current
locale).}
@defproc[(string-locale-ci<? [str1 string?] [str2 string?] ...1)
boolean?]{ Like @scheme[string<?], but both locale-sensitive and
case-insensitive like @scheme[string-locale-ci=?].}
@defproc[(string-locale-ci>? [str1 string?] [str2 string?] ...1)
boolean?]{ Like @scheme[string>?], but both locale-sensitive and
case-insensitive like @scheme[string-locale-ci=?].}
@defproc[(string-locale-upcase [string string?]) string?]{ Like
@scheme[string-upcase], but using locale-specific case-conversion
rules based the value of @scheme[current-locale].}
@defproc[(string-locale-downcase [string string?]) string?]{ Like
@scheme[string-downcase], but using locale-specific case-conversion
rules based the value of @scheme[current-locale].
}

View File

@ -0,0 +1,151 @@
#reader"../docreader.ss"
@require["../manual.ss"]
@require["utils.ss"]
@require-for-syntax[mzscheme]
@define-syntax[def-title-like
(syntax-rules ()
[(_ id result/c x ...) (defproc (id [#:tag tag (or/c false/c string?) #f]
[pre-content any/c] ...0)
result/c
x ...)])]
@define-syntax[def-elem-proc
(syntax-rules ()
[(_ id x ...) (defproc (id [pre-content any/c] ...0)
element?
x ...)])]
@define-syntax[def-style-proc
(syntax-rules ()
[(_ id) @def-elem-proc[id]{Like @scheme[elem], but with style @scheme['id]}])]
@title[#:tag "basic"]{Basic Document Forms}
The @file{basic.ss} libraryprovides functions and forms that can be
used from code written either in Scheme or with @elem["@"]
expressions. For example, the @scheme[title] and @scheme[italic]
functions might be called from Scheme as
@schemeblock[
(title #:tag "how-to" "How to Design " (italic "Great") " Programs")
]
or with an @elem["@"] expression as
@verbatim[
#<<EOS
@title[#:tag "how-to"]{How to Design @italic{Great} Programs}
EOS
]
Although the procedures are mostly design to be used from @elem["@"]
mode, they are easier to document in Scheme mode (partly because we
have Scribble's @file{scheme.ss} and @file{manual.ss}).
@section{Document Structure}
@def-title-like[title title-decl?]{ Generates a @scheme[title-decl] to
be picked up by @scheme[decode] or @scheme[decode-part]. The
@scheme[pre-content]s list is parsed with @scheme[decode-content] for
the title content. If @scheme[tag] is @scheme[#f], a tag string is
generated automatically from the content. The tag string is combined
with the symbol @scheme['section] to form the full tag.}
@def-title-like[section section-start?]{ Like @scheme[title], but
generates a @scheme[section-start] of depth @scheme[0] to be by
@scheme[decode] or @scheme[decode-part].}
@def-title-like[subsection section-start?]{ Like @scheme[section], but
generates a @scheme[section-start] of depth @scheme[1].}
@def-title-like[subsubsection section-start?]{ Like @scheme[section], but
generates a @scheme[section-start] of depth @scheme[2].}
@def-title-like[subsubsub*section paragraph?]{ Similar to
@scheme[section], but merely generates a paragraph that looks like an
unnumbered section heading (for when the nesting gets too deep to
include in a table of contents).}
@defproc[(itemize [itm (or/c whitespace? an-item?)] ...0) itemization?]{
Constructs an itemization given a sequence of items constructed by
@scheme[item]. Whitespace strings among the @scheme[itm]s are
ignored.
}
@defproc[(item pre-flow ...0) item?]{
Creates an item for use with @scheme[itemize]. The
@scheme[pre-flow] list is parsed with @scheme[decode-flow].
}
@defform[(include-section module-path)]{ Requires @scheme[module-path]
and returns its @scheme[doc] export (without making any imports
visible to the enclosing context). Since this form expands to
@scheme[require], it must be used in a module or top-level context.}
@section{Text Styles}
@def-elem-proc[elem]{ Parses the @scheme[pre-content] list using
@scheme[decode-content], and wraps the result as an element with
style @scheme[#f].}
@def-style-proc[italic]
@def-style-proc[bold]
@def-style-proc[tt]
@def-style-proc[subscript]
@def-style-proc[superscript]
@defproc[(hspace [n nonnegative-exact-integer?]) element?]{
Produces an element containing @scheme[n] spaces and style @scheme['hspace].
}
@defproc[(span-class [style-name string?] [pre-content any/c] ...0)
element?]{
Parses the @scheme[pre-content] list using @scheme[decode-content],
and produces an element with style @scheme[style-name].
}
@section{Indexing}
@defproc[(index [words (or/c string? (listof string?))]
[pre-content any/c] ...0)
index-element?] {
Creates an index element given a plain-text string---or list of
strings for a hierarchy, such as @scheme['("strings" "plain")] for a
``plain'' entry until a more general ``strings'' entry. The strings
also serve as the text to render in the index. The
@scheme[pre-content] list, as parsed by @scheme[decode-content] is the
text to appear in place of the element, to which the index entry
refers.
}
@defproc[(index* [words (listof string?)]
[word-contents (listof list?)]
[pre-content any/c] ...0)
index-element?] {
Like @scheme[index], except that @scheme[words] must be a list, and
the list of contents render in the index (in parallel to
@scheme[words]) is supplied as @scheme[word-contents].
}
@defproc[(as-index [pre-content any/c] ...0)
index-element?] {
Like @scheme[index], but the word to index is determined by applying
@scheme[content->string] on the parsed @scheme[pre-content] list.
}
@section{Tables of Contents}
@defproc[(table-of-contents) delayed-flow-element?]{
Returns a flow element that expands to a table of contents for the
enclosing section. For LaTeX output, however, the table of contents
currently spans the entire enclosing document.
}

View File

@ -0,0 +1,111 @@
#reader"../docreader.ss"
@require["../manual.ss"]
@require["utils.ss"]
@title[#:tag "decode"]{Text Decoder}
The @file{decode.ss} library helps you write document content in a
natural way---more like plain text, except for @elem["@"] escapes.
Roughly, it processes a stream of strings to produces instances of the
@file{struct.ss} datatypes (see @secref["struct"]).
At the flow level, decoding recognizes a blank line as a paragraph
separator. At the paragraph-content level, decoding makes just a few
special text conversions:
@itemize{
@item{@litchar{---}: converted to @scheme['mdash], which the HTML render
outputs as an en-dash surrounded by space (so don't put spaces around
@litchar{---} in a document)}
@item{@litchar{--}: converted to @scheme['ndash]}
@item{@litchar{``}: converted to @scheme['ldquo], which is fancy open quotes: ``}
@item{@litchar{''}: converted to @scheme['rdquo], which is fancy closing quotes: ''}
@item{@litchar{'}: converted to @scheme['rsquo], which is a fancy apostrophe: '}
}
@defproc[(decode [lst list?]) part?]{
Decodes a document, producing a part. In @scheme[lst], instances of
@scheme[splice] are inlined into the list. An instance of
@scheme[title-decl] supplies the title for the part. Instances of
@scheme[part-start] at level 0 trigger sub-part parsing. Instances of
@scheme[section] trigger are used as-is as subsections, and instances
of @scheme[paragraph] and other flow-element datatypes are used as-is
in the enclosing flow.
}
@defproc[(decode-part [lst list?]
[tag string?]
[title (or/c false/c list?)]
[depth excat-nonnegative-integer?])
part?]{
Like @scheme[decode], but given a tag for the section, a title (if
@scheme[#f], then a @scheme[title-decl] instance is used if found),
and a depth for @scheme[part-start]s to trigger sub-part parsing.
}
@defproc[(decode-flow [lst list?]) (listof flow-element?)]{
Decodes a flow. A sequence of two or more newlines separated only by
whitespace counts is parsed as a paragraph separator. In @scheme[lst],
instances of @scheme[splice] are inlined into the list. Instances of
@scheme[paragraph] and other flow-element datatypes are used as-is in
the enclosing flow.
}
@defproc[(decode-paragraph [lst list?]) paragraph?]{
Decodes a paragraph.
}
@defproc[(decode-content [lst list?]) list?]{
Decodes a sequence of elements.
}
@defproc[(decode-string [s string?]) list?]{
Decodes a single string to produce a list of elements.
}
@defproc[(whitespace? [s string?]) boolean?]{
Returns @scheme[#t] if @scheme[s] contains only whitespace, @scheme[#f]
otherwise.
}
@defstruct[title-decl ([tag any/c]
[content list?])]{
See @scheme[decode] and @scheme[decode-part].
}
@defstruct[part-start ([depth integer?]
[tag (or/c false/c string?)]
[title list?])]{
See @scheme[decode] and @scheme[decode-part].
}
@defstruct[splice ([run list?])]{
See @scheme[decode], @scheme[decode-part], and @scheme[decode-flow].
}

View File

@ -0,0 +1,18 @@
#reader"../docreader.ss"
@require["../manual.ss"]
@require["utils.ss"]
@title[#:tag "doclang"]{Document Module Languegs}
The @file{doclang.ss} module is suitable for use as a module
language. It provides everything from @scheme[mzscheme], except that
it replaces the @scheme[#%module-begin] form.
The @file{doclang.ss} @scheme[#%module-begin] essentially packages the
body of the module into a call to @scheme[decode], binds the result to
@scheme[doc], and exports @scheme[doc].
Any module-level form other than an expression (e.g., a
@scheme[require] or @scheme[define]) is remains at the top level, and
the @scheme[doc] binding is put at the end of the module. As usual, a
module-top-level @scheme[begin] slices into the module top level.

View File

@ -0,0 +1,13 @@
#reader"../docreader.ss"
@require["../manual.ss"]
@require["../bnf.ss"]
@require["utils.ss"]
@title[#:tag "docreader"]{Document Reader}
The @file{docreader.ss} module is suitable for use with
@schemefont{#reader} at the beginning of a file. It reads the entire
file with @scheme[read-inside-syntax] from Scribble's
@file{reader.ss}, and then wraps the result with @scheme[(module #,
@nonterm{name} (lib "doclang.ss" "scribble") ...)], where
@nonterm{name} is derived from the enclosing file's name.

View File

@ -0,0 +1,56 @@
#reader"../docreader.ss"
@require["../manual.ss"]
@require["utils.ss"]
@title[#:tag "eval"]{Evaluation and Examples}
The @file{eval.ss} library provides utilities for evaluating code at
document-build time and incorporating the results in the document,
especially to show example uses of defined procedures and syntax.
@defform[(interaction datum ...)]{Like @scheme[schemeinput], except
that the result for each input @scheme[datum] is shown on the next
line. The result is determined by evaluating the quoted form of the
datum.
Uses of @scheme[code:comment] and @schemeidfont{code:blank} are
stipped from each @scheme[datum] before evaluation.
If a datum has the form @scheme[(#,(scheme code:line) #,(svar datum)
(#,(scheme code:comment) ...))], then only the @svar[datum] is
evaluated.
If a datum has the form @scheme[(eval:alts #,(svar show-datum) #,(svar
eval-datum))], then @svar[show-datum] is typeset, while
@svar[eval-datum] is evaluated.}
@defform[(interaction-eval datum)]{Evaluates the quoted form of
each @scheme[datum] via @scheme[do-eval] and returns the empty string.}
@defform[(interaction-eval-show datum)]{Evaluates the quoted form of
@scheme[datum] and produces an element represeting the printed form of
the result.}
@defform[(schemeblock+eval datum ...)]{Combines @scheme[schemeblock]
and @scheme[interaction-eval].}
@defform[(schememod+eval name datum ...)]{Combines @scheme[schememod]
and @scheme[interaction-eval].}
@defform[(def+int defn-datum expr-datum ...)]{Like
@scheme[interaction], except the the @scheme[defn-datum] is typeset as
for @scheme[schemeblock] (i.e., no prompt) with a line of space
between the definition and the interactions.}
@defform[(defs+int (defn-datum ...) expr-datum ...)]{Like
@scheme[def+int], but for multiple leading definitions.}
@defform[(examples datum ...)]{Like @scheme[interaction], but with an
``Examples:'' label prefixed.}
@defform[(defexamples datum ...)]{Like @scheme[examples], but each
definition using @scheme[define] among the @scheme[datum]s is typeset
without a prompt, and with space after it.}
@defthing[current-int-namespace parameter?]{A parameter to hold the
namespace used by @scheme[interaction], etc.}

View File

@ -0,0 +1,328 @@
#reader"../docreader.ss"
@require["../manual.ss"]
@require["utils.ss"]
@require-for-syntax[mzscheme]
@title[#:tag "manual"]{PLT Manual Forms}
The @file{manual.ss} module provides all of @file{basic.ss}, and
more...
@; ------------------------------------------------------------------------
@section{Typesetting Code}
@defform[(schemeblock datum ...)]{
Typesets the @scheme[datum] sequence as a table of Scheme code inset
by two spaces. The source locations of the @scheme[datum]s determines
the generated layout. For example,
@schemeblock[
(schemeblock
(define (loop x)
(loop (not x))))
]
produces the output
@schemeblock[
(define (loop x)
(loop (not x)))
]
with the @scheme[(loop (not x))] indented under @scheme[define],
because that's the way it is idented the use of @scheme[schemeblock].
Furthermore, @scheme[define] is typeset as a keyword (bold and black)
and as a hyperlink to @scheme[define]'s definition in the reference
manual, because this document was built using information about the
MzScheme manual. Similarly, @scheme[not] is a hyperlink to the its
definition in the reference manual.
Use @scheme[unsyntax] to escape back to an expression that produces an
@scheme[element]. For example,
@let[([unsyntax #f])
(schemeblock
(schemeblock
(+ 1 (unsyntax (elem (scheme x) (subscript "2"))))))
]
produces
@schemeblock[
(+ 1 (unsyntax (elem (scheme x) (subscript "2"))))
]
The @scheme[unsyntax] form is regonized via
@scheme[module-identifier=?], so if you want to typeset code that
includes @scheme[unsyntax], you can simply hide the usual binding:
@SCHEMEBLOCK[
(schemeblock
(let ([(UNSYNTAX (scheme unsyntax)) #f])
(schemeblock
(syntax (+ 1 (unsyntax x))))))
]
Or use @scheme[SCHEMEBLOCK], whose escape form is @scheme[UNSYNTAX]
instead of @scheme[unsyntax]. See also @scheme[define-code] from
@file{scheme.ss}.
A few other escapes are recognized symbolically:
@itemize{
@item{@scheme[(#,(scheme code:line) datum ...)] typesets as the
sequence of @scheme[datum]s (i.e., without the
@scheme[code:line] wrapper.}
@item{@scheme[(#,(scheme code:comment) content-expr)] typesets as a
comment whose content (i.e., sequence of elements) is produced
by @scheme[content-expr].}
@item{@schemeidfont{code:blank} typesets as a blank line.}
}
}
@defform[(SCHEMEBLOCK datum ...)]{Like @scheme[schemeblock], but with
the expression escape @scheme[UNSYNTAX] instead of @scheme[unsyntax].}
@defform[(schemeblock0 datum ...)]{Like @scheme[schemeblock], but
without insetting the code.}
@defform[(SCHEMEBLOCK0 datum ...)]{Like @scheme[SCHEMEBLOCK], but
without insetting the code.}
@defform[(schemeinput datum ...)]{Like @scheme[schemeblock], but the
@scheme[datum] are typeset after a prompt representing a REPL.}
@defform[(schememod lang datum ...)]{Like @scheme[schemeblock], but
the @scheme[datum] are typeset inside a @schemefont{#module}-form
module whose language is @scheme[lang].}
@defform[(scheme datum ...)]{Like @scheme[schemeblock], but typeset on
a single line and wrapped with its enclosing paragraph, independent of
the formatting of @scheme[datum].}
@defform[(schemeresult datum ...)]{Like @scheme[scheme], but typeset
as a REPL value (i.e., a single color with no hperlinks).}
@defform[(schemeid datum ...)]{Like @scheme[scheme], but typeset
as an unbound identifier (i.e., no coloring or hyperlink).}
@defform[(schememodname datum ...)]{Like @scheme[scheme], but typeset
as a @schemefont{#module} language name.}
@defproc[(litchar [str string?]) element?]{Typesets @scheme[str] as a
representation of literal text. Use this when you have to talk about
the individual characters in a stream of text, as as when documenting
a reader extension.}
@defproc[(verbatim [str string?]) flow-element?]{Typesets @scheme[str]
as a table/paragraph in typewriter font with the linebreaks specified
by newline characters in @scheme[str]. ``Here strings'' are often
useful with @scheme[verbatim].}
@defproc[(schemefont [pre-content any/c] ...0) element?]{Typesets the given
content as uncolored, unhyperlinked Scheme. This procedure is useful
for typesetting thngs like @scheme{#module}, which are not
@scheme[read]able by themselves.}
@defproc[(schemevalfont [pre-content any/c] ...0) element?]{Like
@scheme[schemefont], but colored as a value.}
@defproc[(schemeresultfont [pre-content any/c] ...0) element?]{Like
@scheme[schemefont], but colored as a REPL result.}
@defproc[(schemeidfont [pre-content any/c] ...0) element?]{Like
@scheme[schemefont], but colored as an identifier.}
@defproc[(schemekeywordfont [pre-content any/c] ...0) element?]{Like
@scheme[schemefont], but colored as a syntactic form name.}
@defproc[(procedure [pre-content any/c] ...0) element?]{Typesets the given
content as a procedure name in a REPL result (e.g., in typewrite font
with a @schemefont{#<procedure:} prefix and @schemefont{>} suffix.).}
@defform[(var datum)]{Typesets @scheme[var] as an identifier that is
an argument or sub-form in a procedure being
documented. Normally, the @scheme[defproc] and @scheme[defform]
arrange for @scheme[scheme] to format such identifiers automatically
in the description of the procedure, but use @scheme[var] if that
cannot work for some reason.}
@defform[(svar datum)]{Like @scheme[var], but for subform non-terminals
in a form definition.}
@; ------------------------------------------------------------------------
@section{Definition Reference}
@defform[(defproc (identifier arg-spec ...) result-contract-expr-datum pre-flow ...)]{Produces
a sequence of flow elements (encaptured in a @scheme[splice]) to
document a procedure named @scheme[identifier]. The
@scheme[identifier] is registered so that @scheme[scheme]-typeset uses
of the identifier are hyperlinked to this documentation.
Each @scheme[arg-spec] must have one of the following forms:
@itemize{
@item{@specsubform/inline[(arg-identifier contract-expr-datum)]{---
an argument whose contract is specified by
@scheme[contract-expr-datum] which is typeset via
@scheme[scheme].}}
@item{@specsubform/inline[(arg-identifier contract-expr-datum
default-expr)]{ --- like the previous case, but with a default
value. All arguments with a default value must be grouped
together, but they can be in the middle of required
arguments.}}
@item{@specsubform/inline[(keyword arg-identifier
contract-expr-datum)]{ --- like the first case, but for a
keyword-based argument.}}
@item{@specsubform/inline[(keyword arg-identifier contract-expr-datum
default-expr)]{ --- like the previous case, but with a default
value.}}
@item{@scheme[...0] --- any number of the preceding argument
(normally at the end)}
@item{@scheme[...1] --- one or more of the preceding argument
(normally at the end)}
}
The @scheme[result-contract-expr-datum] is typeset via
@scheme[scheme], and it represents a contract on the procedure's
result.
The @scheme[pre-flow]s list is parsed as a flow that documents the
procedure. In this description, references to @svar[arg-identifier]s
are typeset as procedure arguments.
The typesetting of all data before the @scheme[pre-flow]s ignores the
source layout.}
@defform[(defproc* (((identifier arg-spec ...) result-contract-expr-datum) ...) pre-flow ...)]{Like
@scheme[defproc], but for multiple cases with the same @scheme[identifier].
}
@defform[(defform (identifier . datum) pre-flow ...)]{Produces a
a sequence of flow elements (encaptured in a @scheme[splice]) to
document a syntaic form named by @scheme[identifier]. The
@scheme[identifier] is registered so that @scheme[scheme]-typeset uses
of the identifier are hyperlinked to this documentation.
The @scheme[pre-flow]s list is parsed as a flow that documents the
procedure. In this description, a reference to any identifier in
@scheme[datum] is typeset as a sub-form non-terminal.
The typesetting of @scheme[(identifier . datum)] preserves the source
layout, like @scheme[scheme], and unlike @scheme[defproc].}
@defform[(specsubform/inline datum pre-flow ...)]{Similar to
@scheme[defform], but without any specific identifier being defined,
without the output format that highlights a definition, and with
@scheme[datum] as an element rather than a table. This form is
intended for use when refining the syntax of a non-terminal used in a
@scheme[defform], @scheme[specsubform], or other
@scheme[specsubform/inline]. For example, it is used in the
documentation for @scheme[defproc] in the itemization of possible
shapes for @svar[arg-spec].
The @scheme[pre-flow]s list is parsed as a flow that documents the
procedure. In this description, a reference to any identifier in
@scheme[datum] is typeset as a sub-form non-terminal.}
@defform[(specsubform datum pre-flow ...)]{Like
@scheme[specsubform/inline], but the @scheme[datum] is typeset in the
resulting flow as a table instead of an element.}
@defform[(defthing identifier contract-expr-datum pre-flow ...)]{Like
@scheme[defproc], but for a non-procedure binding.}
@defform[(defstruct struct-name ([field-name contract-expr-datum] ...) pre-flow ...)]{Similar
to @scheme[defform], but for a structure definition.
The @scheme[struct-name] can be either of the following:
@itemize{
@item{@specsubform/inline[identifier]{--- a structure type with no
specified supertype.}}
@item{@specsubform/inline[(identifier super-identifier)]{ --- a structure
type with indicated supertype.}}
}}
@; ------------------------------------------------------------------------
@section{Various String Forms}
@defproc[(defterm [pre-content any/c] ...0) element?]{Typesets the given
content as a defined term (e.g., in italic).}
@defproc[(onscreen [pre-content any/c] ...0) element?]{ Typesets the given
content as a string that appears in a GUI, such as the name of a
button.}
@defproc[(menuitem [menu-name string?] [item-name string?]) element?]{
Typesets the given combination of a GUI's menu and item name.}
@defproc[(file [pre-content any/c] ...0) element?]{Typesets the given content
as a file name (e.g., in typewriter font and in in quotes).}
@defproc[(exec [pre-content any/c] ...0) element?]{Typesets the given content
as a command line (e.g., in typewriter font).}
@; ------------------------------------------------------------------------
@section{Section Links}
@defproc[(secref [tag string?]) element?]{Inserts the hyperlinked
title of the section tagged @scheme[tag].}
@defproc[(seclink [tag string?] [pre-content any/c] ...0) element?]{The content from
@scheme[pre-content] is hyperlinked to the section tagged @scheme[tag].}
@defproc[(schemelink [id symbol?] [pre-content any/c] ...0) element?]{The content from
@scheme[pre-content] is hyperlinked to the definition of @scheme[id].}
@; ------------------------------------------------------------------------
@section{Indexing}
@defproc[(idefterm [pre-content any/c] ...0) element?]{Combines
@scheme[as-index] and @scheme[defterm]. The content normally should be
plurarl, rather than singular.}
@defproc[(pidefterm [pre-content any/c] ...0) element?]{Like
@scheme[idefterm], but plural: adds an ``s'' on the end of the content
for the index entry.}
@; ------------------------------------------------------------------------
@section{Miscellaneous}
@defthing[PLaneT string?]{@scheme["PLaneT"] (to help make sure you get
the letters in the right case).}
@defproc[(void-const) any/c]{Returns @scheme["void"], as opposed to
@scheme[(scheme void)]---but we may eventually find a clearer way to
refer to @void-const in prose.}
@defproc[(centerline [pre-flow any/c] ...0) table?]{Produces a
centered table with the @scheme[pre-flow] parsed by
@scheme[decode-flow].}
@defproc[(commandline [pre-content any/c] ...0) paragraph?]{Produces a
an inset command-line example (e.g., in typewriter font).}

View File

@ -0,0 +1,499 @@
#reader"../docreader.ss"
@require["../manual.ss"]
@require["../bnf.ss"]
@require["utils.ss"]
@title[#:tag "reader"]{Scribble Reader}
The Scribble @|at|-reader is designed to be a convenient facility for
using free-form text in Scheme code, where ``@at'' is chosen as one of
the least-used characters in Scheme code.
You can use the reader via MzScheme's @schemefont{#reader} form:
@schemeblock[
#, @schemefont[#<<EOS
#reader(lib "reader.ss" "scribble")@{This is free-form text!}
EOS
]
]
Note that the reader will only perform a translation from @at
forms to S-expressions. It not give you any bindings to give meaning
to the S-expression.
A PLT Scheme manual more likely starts with
@schemeblock[
#, @schemefont{#reader(lib "docreader.ss" "scribble")}
]
which installs a reader, wraps the file content afterward into a
MzScheme module, and parses the body into a document using
@file{decode.ss}. See @secref["docreader"] for more information.
Another way to use the reader is to use the @scheme[use-at-readtable]
function to switch the current readtable to a readtable that parses
@at forms. You can do this in a single command line:
@commandline{mzscheme -Le reader.ss scribble "(use-at-readtable)"}
In addition to @scheme[read] and @scheme[read-syntax], which are used
by @schemefont{#reader}, the @file{reader.ss} library provides the
procedures @scheme[read-inside] and @scheme[read-inside-syntax]; these
@schemeid[-inner] variants parse as if starting inside a
@litchar["@{"]...@litchar["}"], and they return a (syntactic) list.
@section{Concrete Syntax}
Informally, the concrete syntax of @|at|-commands is
@schemeblock[
#, @BNF-seq[@litchar["@"] @nonterm{cmd}
@litchar{[} @kleenestar{@nonterm{datum}} @litchar{]}
@litchar["{"] @kleenestar{@nonterm{text-body}} @litchar["}"]]
]
where all three parts after @litchar["@"] are optional, but at least one
should be present. (Since the reader will try to see if there is a
"{...body...}" in the input, it can be awkward to use body-less
constructs on an interactive REPL since reading an expression succeeds
only when there is a new expression available.) In the readtable,
@litchar["@"] is set as a terminating reader macro, so if you want to
use it in Scheme code, you need to quote it as @scheme{\@} or the whole
identifier with @scheme[|ba@rs|]. Of course, @litchar["@"] is not treated
specially in Scheme strings, character constants, etc.
Roughly, a form matching the grammar above is read as
@schemeblock[
(#, @nonterm{cmd} #, @kleenestar{@nonterm{datum}} #, @kleenestar{@nonterm{parsed-body}})
]
where @nonterm{parsed-body} is the translation of each
@nonterm{text-body} in the input.
Thus, the initial @nonterm{cmd} determines the Scheme code that
the input is translated into. The common case is when @nonterm{cmd} is a
Scheme identifier, which generates a plain Scheme form.
A @nonterm{text-body} is either a sequence of characters without
@litchar["@"] or newlines, a newline by itself, or the translation of a
@at form. Note that the syntax for @at forms is the same in a
@nonterm{text-body} context as in a Scheme context. A
@nonterm{text-body} that isn't a @at form is converted to a string for
its @nonterm{parsed-body}:
@scribble-examples[
#<<EOS
@foo{bar baz
blah}
EOS
#f
#<<EOS
@foo{bar @baz[3]
blah}
EOS
#f
#<<EOS
@foo{bar @baz{3}
blah}
EOS
#f
#<<EOS
@foo{bar @baz[2 3]{4 5}
blah}
EOS
]
When the above @at forms appear in a Scheme expression context,
the surrounding context must provide a binding for @scheme[foo]
(either as a procedure or macro). To just see the read result for a
@at form, you can always use Scheme's @scheme[quote]:
@scribble-examples[(list @litchar["'@foo{bar}"] @scheme['(foo "bar")])]
@; - - - - - - - - - - - - - - - - - - - - - - - -
@subsection{The Command Part}
Besides being a Scheme identifier, the @nonterm{cmd} part of an @at
form can have Scheme punctuation prefixes, which will end up wrapping
the @italic{whole} expression.
@scribble-examples[
"@`',@foo{blah}"
]
When writing Scheme code, this means that @litchar["@`',@foo{blah}"]
is exactly the same as @litchar["`@',@foo{blah}"] and
@litchar["`',@@foo{blah}"], but unlike the latter two, the first
construct can appear in body texts with the same meaning, whereas the
other two would not work (see below).
Even after Scheme punctuation, the @nonterm{cmd} itself is not limited
to a Scheme identifier; it can be any Scheme expression.
@scribble-examples[
"@(lambda (x) x){blah}"
]
In addition, the command can be omitted altogether, which will omit it
from the translation, resulting in an S-expression that usually
contains, say, just strings:
@scribble-examples[
#<<EOS
@{foo bar
baz}
EOS
#f
#<<EOS
@'{foo bar
baz}
EOS
]
If the command part begins with a @litchar{;} (with no newline between
the @litchar["@"] and the @litchar{;}), then the construct is a
comment. There are two comment forms, one for arbitrary-text and
possibly nested comments, and another one for line comments:
@schemeblock[
#, @BNF-seq[@litchar["@;"] @kleenestar{@nonterm{whitespace}} @litchar["{"] @kleenestar{@nonterm{any}} @litchar["@"]]
#, @BNF-seq[@litchar["@;"] @kleenestar{@nonterm{anythign-else-without-newline}}]
]
In the first form, the commented body must still parse correctly; see
the description of the body syntax below.
Tip: if you're editing in some Scheme-mode, it is useful to comment out
blocks like this:
@verbatim[#<<EOS
@;
{
...
}
EOS
]
or
@verbatim[#<<EOS
@;{
...
;}
EOS
]
otherwise you will probably confuse the editor into treating the file as
having imbalanced parenthesis.
If only the @nonterm{cmd} part is specified of an @at form, then the
result is the command part only, without an extra set of parenthesis.
This makes it suitable for Scheme escapes in body texts. More below,
in the description of the body part.
Finally, note that there are currently no special rules for using
@litchar["@"] in the command itself, which can lead to things like:
@scribble-examples[
"@@foo{bar}{baz}"
]
You should not rely on such behavior, since @litchar["@@"] might be used
differently in the future (e.g., making @litchar["@@"] be ``@at'' in a
body text).
@subsection{The Datum Part}
The datum part can contains arbitrary Scheme expressions, which
are simply stacked before the body text arguments:
@scribble-examples[
"@foo[1 (* 2 3)]{bar}"
"@foo[@bar{...}]{blah}"
]
@italic{This following is going to be removed, I think...}
But there is one change that makes it easy to use for keyword/values:
@litchar{=} is a terminating character in the textual scope, and it if
there is a @BNF-seq[@nonterm{identifier} @litchar{=} @nonterm{expr}]
sequence (spaces optional), then it is converted to
@schemefont{#:}@nonterm{identifier} @nonterm{expr}.
@scribble-examples[
"@foo[(* 2 3) a=b]{bar}"
]
@subsection{The Body Part}
The syntax of the body part is intended to be as convenient as
possible for writing free text. It can contain almost any text---the
only character with special meaning is @litchar["@"]. In addition,
@litchar["{"], @litchar["}"], @litchar["|"], and @litchar["\\"] can
have special meanings, but only in a few contexts. As described
above, the text turns to a sequence of string arguments for the
resulting form. Spaces at the beginning of lines are discarded (but
see the information about indentation below), and newlines turn to
individual @scheme["\n"] strings. (Spcaces are preserved on a
single-line text.) As part of trying to do the ``right thing,'' an
empty line at the beginning and at the end are discarded, so:
@scribble-examples[
#<<EOS
@foo{
bar
}
EOS
#f
"@foo{bar}"
"@foo{ bar }"
]
If @litchar["@"] appears in a body, then it is interpreted as Scheme
code, which means that the @|at|-reader will be applied recursively,
and the resulting syntax will appear as an argument, among other
string contents.
@scribble-examples[
"@foo{a @bar{b} c}"
]
If the nested @at construct has only a command---no body part---then
it does not appear in a subform. Given that the command part can be
any Scheme expression, this makes @at a general escape to arbitrary
Scheme code.
@scribble-examples[
"@foo{a @bar c}"
"@foo{a @(bar 2) c}"
]
In some cases, you may want to use a Scheme identifier (or a number or
a boolean) in a position that touches other text that can make an
identifier; in these situations you should surround the Scheme
identifier (or number or boolean) by a pair of @litchar["|"]. The
text inside the bars is parsed as a Scheme expression, but if that
fails, it is used as a quoted identifier; do not rely on this
behavior, and avoid using whitespace inside the bars. Also, if bars
are used, then no body text is used even if they are followed by
braces (see the next paragraph).
@scribble-examples[
"@foo{foo @bar foo}"
"@foo{foo@bar.}"
"@foo{foo@|bar|.}"
"@foo{foo@3.}"
"@foo{foo@|3|.}"
"@foo{foo@|(f 1)|{bar}.}"
]
Braces are only problematic because a @litchar["}"] is used to mark
the end of the text. They are therefore allowed, as long as they are
balanced.
@scribble-examples[
"@foo{f{o}o}"]
]
There is also an alternative syntax for the body, one that specifies a
new marker for the end: use @litchar["|{"] for the openning marker,
optionally with additional characters between them (excluding
@litchar["{"], whitespace, and alphanumerics); the matching closing
marker should be the mirrored form of the openning marker (reverse the
characters and swap round, square, curly, and angle parentheses).
@scribble-examples[
"@foo|{...}|"
"@foo|{foo{{{bar}|"
"@foo|<{{foo{{{bar}}>|"
]
More simply, if you get into too much trouble with special characters
in a body, then it's often a good idea to use the Scheme part,
instead.
@scribble-examples[
"@foo[\"}\"]"
"@foo[\"@literally{}\"]"
]
@; - - - - - - - - - - - - - - - - - - - - - - - -
@subsubsub*section{Quoting in Body Texts}
To quote braces or @at, precede them with a backslash. Note that this
is an irregular use of backslash quoting! To use @litchar["\\@"] in
your text, simply precede it with a backslash. The general rule is
that to use N backslashes-and-a-special-character, you should precede
it with one extra backslash. Any other use of a backslash (one that
is not followed by more back-slashes and a special character) is
preserved in the text as usual.
@scribble-examples[
"@foo{b\\@ar}"
"@foo{b\\\\@ar}"
"@foo{b\\\\\\@ar}"
"@foo{b\\{\\@\\@ar}"
"@foo{b\\ar}"
"@foo{b\\\\ar}"
]
@; - - - - - - - - - - - - - - - - - - - - - - - -
@subsubsub*section{Newlines and Indentation}
When indentation is used, all-space indentation string syntaxes are
perpended to the beginning of each line. The rule for adding these
string is:
@itemize{
@item{A spaces-string is added to each line according to its distance from
the leftmost syntax object;}
@item{The first string is not prepended with indentation if it appears on
the first line of output.}
}
@scribble-examples[
#<<EOS
@foo{
bar
baz
bbb}
EOS
#f
#<<EOS
@foo{bar
baz
bbb}
EOS
#f
#<<EOS
@foo{ bar
baz
bbb}
EOS
#f
#<<EOS
@foo{bar
baz
bbb}
EOS
#f
#<<EOS
@foo{ bar
baz
bbb}
EOS
#f
#<<EOS
@foo{ bar
baz
bbb}
EOS
]
Additional notes:
@itemize{
@item{You can identify indentation strings at the syntax level by the fact
that they have the same location information as the following syntax
object.}
@item{This mechanism depends on line and column number information
(@scheme[use-at-readtable] turns them on for the current input port);}
@item{To use this mechanism with nested commands that should preserve
indentation, you will need to do some additional work since the nested
use will have only its own indentation;}
@item{When using it on a command-line, you note that the reader is not aware
of the ``> '' prompt, which might lead to confusing results.}
}
@italic{The following is likely to change.}
For situations where spaces at the beginning of lines matter (various
verbatim environments), you should begin a line with a @litchar["|"].
It has no other special meaning -- so to use a @litchar["|"] as the
first character in the text, simply use another before it.
@scribble-examples[
#<<EOS
@code{
|(define (foo x)
| |error|)
}
EOS
]
In other situations, newlines matter; you might want to avoid a
newline token in some place. To avoid a newline and still break the
source line, use a line comment. As in TeX, these will consume text
up-to and including the end of the line and all following whitespace.
@bold{@italic{The following examples from the original docs didn't
work. They have been changed!}}
@scribble-examples[
#<<EOS
@foo{bar @;
baz@;
!}
EOS
] @bold{The "!" above used to be a "."}
A @litchar["|"] that follows this is still used for marking the
beginning of the text:
@scribble-examples[
#<<EOS
@foo{bar @;
baz@;
? .}
EOS
] @bold{The "?" above used to be a "|", which is surely part of the point.}
@; ------------------------------------------------------------------------
@subsection{How To Use the Reader}
The reader can be used in any way you want. All you need is to use
function names that you bind. You can even use quasi-quotes, skipping
the need for functions, for example:
@verbatim[
#<<EOS
> (define (important . text) @`b{@u{@big{@,@text}}})
> (important @`p{This is an important announcement!
Read it!})
(b (u (big (p "This is an important announcement!" "\n" "Read it!"))))
EOS
]

View File

@ -0,0 +1,31 @@
#reader"../docreader.ss"
@require["../manual.ss"]
@require["utils.ss"]
@title[#:tag "renderer"]{Renderer}
A renderer is an object that provides two main methods:
@scheme[collect] and @scheme[render]. The first method is called to
collect global information about the document, including information
that spans multiple documents rendered together; the collection pass
tends to be format-independent, and it usually implemented completely
by the base renderer. The latter method generates the actual output,
which is naturally specific to a particular format.
The @file{base-render.ss} module provides @scheme[render%], which
implements the core of a renderer. The @file{html-renderer.ss},
@file{latex-renderer.ss}, and @file{text-renderer.ss} modules each
provide @scheme[renderer-mixin] to extend the base. The
@file{html-renderer.ss} module also provides
@scheme[multi-renderer-mixin] to produce multi-file HTML instead
instead of single-file HTML.
The mixin structure is meant to support document-specific extensions
to the renderers. For example, the @exec{scribble} command-line tool
might, in the future, extract rendering mixins from a document module
(in addition to the document proper).
See @file{base-render.ss} for more information about the methods of
the renderer. Documents built with higher layers, such as
@file{manual.ss}, generally do not call the render object's methods
directly.

View File

@ -0,0 +1,90 @@
#reader"../docreader.ss"
@require["../manual.ss"]
@require["../bnf.ss"]
@require["utils.ss"]
@title{PLT Scribble}
The @file{scribble} collection provides libraries that can be used to
create documents from Scheme.
@table-of-contents[]
@; ------------------------------------------------------------------------
@section{Scribble Layers}
Scribble is made of independently usable parts. For example, the
Scribble reader can be used in any situation that requires lots of
free-form text. You can also skip Scribble's special reader support,
and instead use the document-generation structure directly.
The layers are:
@itemize{
@item{@file{reader.ss}: a reader that extends the syntax of Scheme
with @at forms for conveniently embedding a mixin of text and
escapes. See @secref["reader"].}
@item{@file{struct.ss}: a set of document datatypes, which define the
basic layout of a document. See @secref["struct"].}
@item{@file{base-render.ss} with @file{html-render.ss},
@file{latex-render.ss}, or @file{text-render.ss}: A base
renderer and mixins that generate documents in various formats
from instances of the @file{struct.ss} datatype. See
@secref["renderer"].}
@item{@file{decode.ss}: Processes a stream of text, section-start
markers, etc. to produce instances of the @file{struct.ss}
datatype. See @secref["decode"].}
@item{@file{doclang.ss}: to be used for the initial import of a
module; processes the module top level through
@file{decode.ss}, and otherwise provides all of
@scheme[mzscheme]. See @secref["doclang"].}
@item{@file{docreader.ss}: a reader that is meant to tbe used to
process an entire file; it essentially combines
@file{reader.ss} with @file{doclang.ss}. See
@secref["docreader"].}
@item{@file{basic.ss}: a library of basic document operators---such
as @scheme[title], @scheme[section], and @scheme[secref]---for
use with @file{decode.ss} and a renderer. See
@secref["basic"].}
@item{@file{scheme.ss}: a library of support functions for
typesetting Scheme code.}
@item{@file{manual.ss}: a library of support functions for writing
PLT Scheme documentation; re-exports @file{basic.ss}. See
@secref["manual"].}
@item{@file{eval.ss}: a library of support functions for ealuating
code at document-build time, especially for showing
examples. See @secref["eval"].}
@item{@file{bnf.ss}: a library of support functions for writing
grammars.}
}
The @exec{scribble} command-line utility works with a module that
exports a @scheme{struct.ss}-based document, generating output with a
specified renderer. More specifically, the executable installs a
renderer, loads the specified modules and extracts the @scheme[doc]
export of each (which must be an instance of @scheme[section] from
@file{struct.ss}), and renders each. Use @exec{scribble -h} for more
information.
@; ------------------------------------------------------------------------
@include-section["reader.scrbl"]
@include-section["struct.scrbl"]
@include-section["renderer.scrbl"]
@include-section["decode.scrbl"]
@include-section["doclang.scrbl"]
@include-section["docreader.scrbl"]
@include-section["basic.scrbl"]
@include-section["manual.scrbl"]
@include-section["eval.scrbl"]

View File

@ -0,0 +1,212 @@
#reader"../docreader.ss"
@require["../manual.ss"]
@require["utils.ss"]
@title[#:tag "struct"]{Document Structures}
A single document is reprsented as a @defterm{part}:
@itemize{
@item{A @defterm{part} is an instance of @scheme[part]; it has a
title @defterm{content}, an initial @defterm{flow}, and a list
of subsection @defterm{part}s. After the ``collect'' phase of
rendering, it also has @defterm{collected info}. An
@scheme[unnumbered-part] is the same as a @scheme[part], but it
isn't numbered.}
@item{A @defterm{flow} is an instance of @scheme[flow]; it has a list
of @defterm{flow element}s.}
@item{A @defterm{flow element} is either a @defterm{table}, an
@defterm{itemization}, @defterm{paragraph}, or a
@defterm{delayed flow element}.
@itemize{
@item{A @defterm{table} is an instance of @scheme[table]; it has a
list of list of @defterm{flow}s with a particular style.}
@item{A @defterm{itemization} is an instance of @scheme[itemization];
it has a list of flows.}
@item{A @defterm{paragraph} is an instance of @scheme[paragraph]; it
has a list of @defterm{element}s.
@itemize{
@item{An element can be a string, one of a few symbols, an instance of
@scheme[element] (possibly @scheme[link-element],
@scheme[target-element], or
@scheme[index-element]), a @defterm{delayed
element}, or anything else allowed by the current
renderer.
@itemize{
@item{A string element is included in the result
document verbatim.}
@item{A symbol element is either @scheme['mdash],
@scheme['ndash], @scheme['ldquo],
@scheme['lsquo], @scheme['rsquo], or
@scheme['rarr]; it is drawn as the
corresponding HTML entity.}
@item{An instance of @scheme[element] has a list of
@defterm{element}s plus a style. The style's
interpretation depends on the rendrer; it can
be one of a few special symbols that are
recognized by all renderers: @scheme['tt],
@scheme['italic], @scheme['bold],
@scheme['sf], @scheme['subscript],
@scheme['superscript], or @scheme['hspace].
A string corresponds to a CSS class, LaTeX
macro, or something else renderer-specific.
Instances of @scheme[target-url] and
@scheme[image-file] may also be supported.}
@item{An instance of @scheme[link-element] has a
@defterm{tag} for the target of the link.}
@item{An instance of @scheme[target-element] has a
@defterm{tag} to be referenced by
@scheme[link-element]s.}
@item{An instance of @scheme[index-element] has a
@defterm{tag} (as a target), a list of
strings for the keywords (for sorting and
search), and a list of @defterm{element}s to
appear in the end-of-document index.}
@item{A @defterm{delayed element} is an instance of
@scheme[delayed-element], which has a
procedure that produces a
@defterm{element}. The ``collect'' phase of
rendering ignores delayed flow elements.}
}}}}
@item{A @defterm{delayed flow element} is an instance of
@scheme[delayed-flow-element], which has a procedure that
produces a @defterm{flow element}. The ``collect'' phase
of rendering ignores delayed flow elements.}
}}
@item{The @defterm{collected info} of a part includes its number, its
parent part (or @scheme[#f]), and information about link
targets and index entries within the part.}
@item{A @defterm{tag} is eiter a string or a list containing a symbol
and a string.}
}
Note that there's no difference between a part and a full document. A
particular source module just as easily defines a subsection
(incoprated via @scheme[include-section]) as a document.
@defstruct[part ([tag (or/c false/c tag?)]
[title-content (or/c false/c list?)]
[collected-info (or/c false/c collected-info?)]
[flow flow?]
[parts (listof part?)])]{
}
@defstruct[(unnumbered-part part) ()]{
}
@defstruct[flow ([paragraphs (listof flow-element?)])]{
}
@defstruct[paragraph ([content list?])]{
}
@defstruct[table ([style any/c]
[flowss (listof (listof flow?))])]{
}
@defstruct[delayed-flow-element ([render (any/c part? any/c . -> . flow-element?)])]{
For the @scheme[render] procedure, the first argument corresponds to
the rendering context, the second to the immediately enclosing
section, and the last argument correspond to global information
(possibly psanning multiple documents).
}
@defstruct[itemization ([flows (listof flow?)])]{
}
@defstruct[element ([style any/c]
[content list?])]{
}
@defstruct[(target-element element) ([tag tag?])]{
}
@defstruct[(link-element element) ([tag any/c]
[complain-if-fail? boolean?])]{
}
@defstruct[(index-element element) ([tag tag?]
[plain-seq (listof string?)]
[entry-seq list?])]{
}
@defstruct[delayed-element ([render (any/c part? any/c . -> . list?)])]{
The @scheme[render] procedure's arguments are the same as for
@scheme[delayed-flow-element]. Unlike @scheme[delayed-flow-element],
the result of the @scheme[render] procedure's argument is remembered
on the first call. Furthemore, the element can be marshelled (e.g.,
for an index entry or a section-title entry) only if it has been
rendered first.
}
@defstruct[collected-info ([number (listof (or/c false/c integer?))]
[parent (or/c false/c part?)]
[info any/c])]{
}
@defproc[(flow-element? [v any/c]) boolean?]{
Returns @scheme[#t] if @scheme[v] is a @scheme[paragraph],
@scheme[table], @scheme[itemization], or
@scheme[delayed-flow-element], @scheme[#f] otherwise.
}
@defproc[(tag? [v any/c]) boolean?]{
Returns @scheme[#t] if @scheme[v] is acceptable as a link tag,
@scheme[#f], otherwise. Currently, an acceptable tag is either a
string or a list containing a symbol and a string.
}
@defproc[(content->string (content list?)) string?]{
Converts a list of elements to a single string (essentially
rendering the content as ``plain text'').
}

View File

@ -0,0 +1,44 @@
(module utils mzscheme
(require "../struct.ss"
"../manual.ss"
(prefix scheme: "../scheme.ss")
(prefix scribble: "../reader.ss")
(lib "string.ss"))
(provide at
litchar/lines
scribble-examples)
(define at "@")
(define (litchar/lines s)
(let ([strs (regexp-split #rx"\n" s)])
(if (= 1 (length strs))
(litchar s)
(make-table
#f
(map (lambda (s)
(list (make-flow (list (make-paragraph (list (litchar s)))))))
strs)))))
(define (as-flow e)
(make-flow (list (if (flow-element? e)
e
(make-paragraph (list e))))))
(define spacer (hspace 2))
(define (scribble-examples . lines)
(make-table
#f
(map (lambda (line)
(let ([line (if (string? line)
(list (litchar/lines line)
(scheme:to-element (scribble:read (open-input-string line))))
line)])
(list (as-flow spacer)
(as-flow (if line (car line) ""))
(as-flow (if line (make-paragraph (list spacer "reads as" spacer)) ""))
(as-flow (if line (cadr line) "")))))
lines))))

View File

@ -0,0 +1,38 @@
(module to-html mzscheme
(require (lib "dirs.ss" "setup")
(lib "run.ss" "scribble")
(lib "file.ss"))
(provide to-html)
(define (to-html multi? core? docs names)
(let ([main-doc-dir (find-doc-dir)]
[dir (collection-path "scribblings")])
(unless main-doc-dir
(error "cannot find installation doc directory"))
(let ([doc-dir (if multi?
main-doc-dir
(build-path main-doc-dir (car names)))])
(unless multi?
(make-directory* doc-dir))
(parameterize ([current-directory doc-dir]
[current-render-mixin (if multi?
multi-html:render-mixin
html:render-mixin)]
[current-info-output-file (if core?
(build-path main-doc-dir
"reference"
"core-info-html.data")
(current-info-output-file))]
[current-info-input-files (append
(if core?
null
(list (build-path main-doc-dir
"reference"
"core-info-html.data")))
(current-info-input-files))])
(build-docs docs (if multi?
names
(list "index"))))))))