diff --git a/collects/scribblings/core.ss b/collects/scribblings/core.ss new file mode 100644 index 0000000000..9d54f028f9 --- /dev/null +++ b/collects/scribblings/core.ss @@ -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")))) + + diff --git a/collects/scribblings/doc-installer.ss b/collects/scribblings/doc-installer.ss new file mode 100644 index 0000000000..b53e7e017b --- /dev/null +++ b/collects/scribblings/doc-installer.ss @@ -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)))))) diff --git a/collects/scribblings/guide/guide-utils.ss b/collects/scribblings/guide/guide-utils.ss new file mode 100644 index 0000000000..4878de9c86 --- /dev/null +++ b/collects/scribblings/guide/guide-utils.ss @@ -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))) + + + diff --git a/collects/scribblings/guide/guide.scrbl b/collects/scribblings/guide/guide.scrbl new file mode 100644 index 0000000000..221e63ec30 --- /dev/null +++ b/collects/scribblings/guide/guide.scrbl @@ -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"] diff --git a/collects/scribblings/guide/lists.scrbl b/collects/scribblings/guide/lists.scrbl new file mode 100644 index 0000000000..23fde40281 --- /dev/null +++ b/collects/scribblings/guide/lists.scrbl @@ -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[ +#<= 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"]. diff --git a/collects/scribblings/guide/truth.scrbl b/collects/scribblings/guide/truth.scrbl new file mode 100644 index 0000000000..9cb843b0ce --- /dev/null +++ b/collects/scribblings/guide/truth.scrbl @@ -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...] + diff --git a/collects/scribblings/guide/welcome.scrbl b/collects/scribblings/guide/welcome.scrbl new file mode 100644 index 0000000000..4e6d757389 --- /dev/null +++ b/collects/scribblings/guide/welcome.scrbl @@ -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. diff --git a/collects/scribblings/info.ss b/collects/scribblings/info.ss new file mode 100644 index 0000000000..45d31cb27e --- /dev/null +++ b/collects/scribblings/info.ss @@ -0,0 +1,3 @@ +(module info (lib "infotab.ss" "setup") + (define name "Scribblings") + (define post-install-collection "doc-installer.ss")) diff --git a/collects/scribblings/quick.ss b/collects/scribblings/quick.ss new file mode 100644 index 0000000000..e38beab004 --- /dev/null +++ b/collects/scribblings/quick.ss @@ -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")))) diff --git a/collects/scribblings/quick/art.png b/collects/scribblings/quick/art.png new file mode 100644 index 0000000000..2c56b69431 Binary files /dev/null and b/collects/scribblings/quick/art.png differ diff --git a/collects/scribblings/quick/exn.ss b/collects/scribblings/quick/exn.ss new file mode 100644 index 0000000000..ce3de9a633 --- /dev/null +++ b/collects/scribblings/quick/exn.ss @@ -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%)) + diff --git a/collects/scribblings/quick/images/README.txt b/collects/scribblings/quick/images/README.txt new file mode 100644 index 0000000000..21bbe89fef --- /dev/null +++ b/collects/scribblings/quick/images/README.txt @@ -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. diff --git a/collects/scribblings/quick/images/exprs.dat b/collects/scribblings/quick/images/exprs.dat new file mode 100644 index 0000000000..16719cab09 --- /dev/null +++ b/collects/scribblings/quick/images/exprs.dat @@ -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]"))))) diff --git a/collects/scribblings/quick/images/img0.png b/collects/scribblings/quick/images/img0.png new file mode 100644 index 0000000000..874a010aca Binary files /dev/null and b/collects/scribblings/quick/images/img0.png differ diff --git a/collects/scribblings/quick/images/img1.png b/collects/scribblings/quick/images/img1.png new file mode 100644 index 0000000000..dad8e28ec9 Binary files /dev/null and b/collects/scribblings/quick/images/img1.png differ diff --git a/collects/scribblings/quick/images/img10.png b/collects/scribblings/quick/images/img10.png new file mode 100644 index 0000000000..5df51e54d8 Binary files /dev/null and b/collects/scribblings/quick/images/img10.png differ diff --git a/collects/scribblings/quick/images/img11.png b/collects/scribblings/quick/images/img11.png new file mode 100644 index 0000000000..9d03e68e45 Binary files /dev/null and b/collects/scribblings/quick/images/img11.png differ diff --git a/collects/scribblings/quick/images/img12.png b/collects/scribblings/quick/images/img12.png new file mode 100644 index 0000000000..fa40ec0c6d Binary files /dev/null and b/collects/scribblings/quick/images/img12.png differ diff --git a/collects/scribblings/quick/images/img13.png b/collects/scribblings/quick/images/img13.png new file mode 100644 index 0000000000..5716b93b17 Binary files /dev/null and b/collects/scribblings/quick/images/img13.png differ diff --git a/collects/scribblings/quick/images/img14.png b/collects/scribblings/quick/images/img14.png new file mode 100644 index 0000000000..29ee39aab5 Binary files /dev/null and b/collects/scribblings/quick/images/img14.png differ diff --git a/collects/scribblings/quick/images/img15.png b/collects/scribblings/quick/images/img15.png new file mode 100644 index 0000000000..e2eb4ca1f3 Binary files /dev/null and b/collects/scribblings/quick/images/img15.png differ diff --git a/collects/scribblings/quick/images/img16.png b/collects/scribblings/quick/images/img16.png new file mode 100644 index 0000000000..19c3aef5ff Binary files /dev/null and b/collects/scribblings/quick/images/img16.png differ diff --git a/collects/scribblings/quick/images/img17.png b/collects/scribblings/quick/images/img17.png new file mode 100644 index 0000000000..874a010aca Binary files /dev/null and b/collects/scribblings/quick/images/img17.png differ diff --git a/collects/scribblings/quick/images/img18.png b/collects/scribblings/quick/images/img18.png new file mode 100644 index 0000000000..defc0a4349 Binary files /dev/null and b/collects/scribblings/quick/images/img18.png differ diff --git a/collects/scribblings/quick/images/img19.png b/collects/scribblings/quick/images/img19.png new file mode 100644 index 0000000000..c01258374c Binary files /dev/null and b/collects/scribblings/quick/images/img19.png differ diff --git a/collects/scribblings/quick/images/img2.png b/collects/scribblings/quick/images/img2.png new file mode 100644 index 0000000000..28da54b764 Binary files /dev/null and b/collects/scribblings/quick/images/img2.png differ diff --git a/collects/scribblings/quick/images/img20.png b/collects/scribblings/quick/images/img20.png new file mode 100644 index 0000000000..bcef5d38b1 Binary files /dev/null and b/collects/scribblings/quick/images/img20.png differ diff --git a/collects/scribblings/quick/images/img21.png b/collects/scribblings/quick/images/img21.png new file mode 100644 index 0000000000..4a9e94375d Binary files /dev/null and b/collects/scribblings/quick/images/img21.png differ diff --git a/collects/scribblings/quick/images/img22.png b/collects/scribblings/quick/images/img22.png new file mode 100644 index 0000000000..e41b869fd2 Binary files /dev/null and b/collects/scribblings/quick/images/img22.png differ diff --git a/collects/scribblings/quick/images/img23.png b/collects/scribblings/quick/images/img23.png new file mode 100644 index 0000000000..a0eab57204 Binary files /dev/null and b/collects/scribblings/quick/images/img23.png differ diff --git a/collects/scribblings/quick/images/img24.png b/collects/scribblings/quick/images/img24.png new file mode 100644 index 0000000000..799dff9896 Binary files /dev/null and b/collects/scribblings/quick/images/img24.png differ diff --git a/collects/scribblings/quick/images/img25.png b/collects/scribblings/quick/images/img25.png new file mode 100644 index 0000000000..e4d4b58336 Binary files /dev/null and b/collects/scribblings/quick/images/img25.png differ diff --git a/collects/scribblings/quick/images/img26.png b/collects/scribblings/quick/images/img26.png new file mode 100644 index 0000000000..9978b1ec2d Binary files /dev/null and b/collects/scribblings/quick/images/img26.png differ diff --git a/collects/scribblings/quick/images/img27.png b/collects/scribblings/quick/images/img27.png new file mode 100644 index 0000000000..994c76743d Binary files /dev/null and b/collects/scribblings/quick/images/img27.png differ diff --git a/collects/scribblings/quick/images/img28.png b/collects/scribblings/quick/images/img28.png new file mode 100644 index 0000000000..e3e6e12afe Binary files /dev/null and b/collects/scribblings/quick/images/img28.png differ diff --git a/collects/scribblings/quick/images/img29.png b/collects/scribblings/quick/images/img29.png new file mode 100644 index 0000000000..1166306162 Binary files /dev/null and b/collects/scribblings/quick/images/img29.png differ diff --git a/collects/scribblings/quick/images/img3.png b/collects/scribblings/quick/images/img3.png new file mode 100644 index 0000000000..dad8e28ec9 Binary files /dev/null and b/collects/scribblings/quick/images/img3.png differ diff --git a/collects/scribblings/quick/images/img4.png b/collects/scribblings/quick/images/img4.png new file mode 100644 index 0000000000..28da54b764 Binary files /dev/null and b/collects/scribblings/quick/images/img4.png differ diff --git a/collects/scribblings/quick/images/img5.png b/collects/scribblings/quick/images/img5.png new file mode 100644 index 0000000000..8358c10bd4 Binary files /dev/null and b/collects/scribblings/quick/images/img5.png differ diff --git a/collects/scribblings/quick/images/img6.png b/collects/scribblings/quick/images/img6.png new file mode 100644 index 0000000000..defc0a4349 Binary files /dev/null and b/collects/scribblings/quick/images/img6.png differ diff --git a/collects/scribblings/quick/images/img7.png b/collects/scribblings/quick/images/img7.png new file mode 100644 index 0000000000..ab26eae849 Binary files /dev/null and b/collects/scribblings/quick/images/img7.png differ diff --git a/collects/scribblings/quick/images/img8.png b/collects/scribblings/quick/images/img8.png new file mode 100644 index 0000000000..aadb50cf8a Binary files /dev/null and b/collects/scribblings/quick/images/img8.png differ diff --git a/collects/scribblings/quick/images/img9.png b/collects/scribblings/quick/images/img9.png new file mode 100644 index 0000000000..0dca5c1ff8 Binary files /dev/null and b/collects/scribblings/quick/images/img9.png differ diff --git a/collects/scribblings/quick/mreval.ss b/collects/scribblings/quick/mreval.ss new file mode 100644 index 0000000000..da536fe0f5 --- /dev/null +++ b/collects/scribblings/quick/mreval.ss @@ -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]))) diff --git a/collects/scribblings/quick/quick.scrbl b/collects/scribblings/quick/quick.scrbl new file mode 100644 index 0000000000..c503c9fbbe --- /dev/null +++ b/collects/scribblings/quick/quick.scrbl @@ -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}. diff --git a/collects/scribblings/reference/bytes.scrbl b/collects/scribblings/reference/bytes.scrbl new file mode 100644 index 0000000000..a313bd2509 --- /dev/null +++ b/collects/scribblings/reference/bytes.scrbl @@ -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? [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} + diff --git a/collects/scribblings/reference/chars.scrbl b/collects/scribblings/reference/chars.scrbl new file mode 100644 index 0000000000..aab28ad48d --- /dev/null +++ b/collects/scribblings/reference/chars.scrbl @@ -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). diff --git a/collects/scribblings/reference/data.scrbl b/collects/scribblings/reference/data.scrbl new file mode 100644 index 0000000000..ab8825fe82 --- /dev/null +++ b/collects/scribblings/reference/data.scrbl @@ -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.} + + diff --git a/collects/scribblings/reference/mz.ss b/collects/scribblings/reference/mz.ss new file mode 100644 index 0000000000..f94d119d08 --- /dev/null +++ b/collects/scribblings/reference/mz.ss @@ -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)) diff --git a/collects/scribblings/reference/numbers.scrbl b/collects/scribblings/reference/numbers.scrbl new file mode 100644 index 0000000000..2a4c1945c3 --- /dev/null +++ b/collects/scribblings/reference/numbers.scrbl @@ -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)] +} \ No newline at end of file diff --git a/collects/scribblings/reference/read.scrbl b/collects/scribblings/reference/read.scrbl new file mode 100644 index 0000000000..235205142f --- /dev/null +++ b/collects/scribblings/reference/read.scrbl @@ -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]. diff --git a/collects/scribblings/reference/read.txt b/collects/scribblings/reference/read.txt new file mode 100644 index 0000000000..bb44175403 --- /dev/null +++ b/collects/scribblings/reference/read.txt @@ -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. +|# diff --git a/collects/scribblings/reference/reader-example.ss b/collects/scribblings/reference/reader-example.ss new file mode 100644 index 0000000000..19f28c9ad1 --- /dev/null +++ b/collects/scribblings/reference/reader-example.ss @@ -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))))))])))) + diff --git a/collects/scribblings/reference/reference.scrbl b/collects/scribblings/reference/reference.scrbl new file mode 100644 index 0000000000..e30753ca8b --- /dev/null +++ b/collects/scribblings/reference/reference.scrbl @@ -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"] diff --git a/collects/scribblings/reference/strings.scrbl b/collects/scribblings/reference/strings.scrbl new file mode 100644 index 0000000000..abfaff52f9 --- /dev/null +++ b/collects/scribblings/reference/strings.scrbl @@ -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? [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?]{ + @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 locale-specific like + @scheme[string-locale? [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]. +} \ No newline at end of file diff --git a/collects/scribblings/scribble/basic.scrbl b/collects/scribblings/scribble/basic.scrbl new file mode 100644 index 0000000000..f89f269107 --- /dev/null +++ b/collects/scribblings/scribble/basic.scrbl @@ -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[ +#<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. +} diff --git a/collects/scribblings/scribble/decode.scrbl b/collects/scribblings/scribble/decode.scrbl new file mode 100644 index 0000000000..1e8e2c8e12 --- /dev/null +++ b/collects/scribblings/scribble/decode.scrbl @@ -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]. + +} + diff --git a/collects/scribblings/scribble/doclang.scrbl b/collects/scribblings/scribble/doclang.scrbl new file mode 100644 index 0000000000..53ee0ed68b --- /dev/null +++ b/collects/scribblings/scribble/doclang.scrbl @@ -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. diff --git a/collects/scribblings/scribble/docreader.scrbl b/collects/scribblings/scribble/docreader.scrbl new file mode 100644 index 0000000000..3806481403 --- /dev/null +++ b/collects/scribblings/scribble/docreader.scrbl @@ -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. diff --git a/collects/scribblings/scribble/eval.scrbl b/collects/scribblings/scribble/eval.scrbl new file mode 100644 index 0000000000..3feff19bbd --- /dev/null +++ b/collects/scribblings/scribble/eval.scrbl @@ -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.} diff --git a/collects/scribblings/scribble/manual.scrbl b/collects/scribblings/scribble/manual.scrbl new file mode 100644 index 0000000000..221fad0df5 --- /dev/null +++ b/collects/scribblings/scribble/manual.scrbl @@ -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{#} 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).} diff --git a/collects/scribblings/scribble/reader.scrbl b/collects/scribblings/scribble/reader.scrbl new file mode 100644 index 0000000000..4e1f570da9 --- /dev/null +++ b/collects/scribblings/scribble/reader.scrbl @@ -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[#<|" +] + +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[ +#< '' 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[ +#< (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 +] diff --git a/collects/scribblings/scribble/renderer.scrbl b/collects/scribblings/scribble/renderer.scrbl new file mode 100644 index 0000000000..0d3a19fbc6 --- /dev/null +++ b/collects/scribblings/scribble/renderer.scrbl @@ -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. diff --git a/collects/scribblings/scribble/scribble.scrbl b/collects/scribblings/scribble/scribble.scrbl new file mode 100644 index 0000000000..5eaab8545b --- /dev/null +++ b/collects/scribblings/scribble/scribble.scrbl @@ -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"] diff --git a/collects/scribblings/scribble/struct.scrbl b/collects/scribblings/scribble/struct.scrbl new file mode 100644 index 0000000000..9371830b5c --- /dev/null +++ b/collects/scribblings/scribble/struct.scrbl @@ -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''). + +} + diff --git a/collects/scribblings/scribble/utils.ss b/collects/scribblings/scribble/utils.ss new file mode 100644 index 0000000000..15795a8264 --- /dev/null +++ b/collects/scribblings/scribble/utils.ss @@ -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)))) diff --git a/collects/scribblings/to-html.ss b/collects/scribblings/to-html.ss new file mode 100644 index 0000000000..1bf576f769 --- /dev/null +++ b/collects/scribblings/to-html.ss @@ -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")))))))) +