doc work
svn: r6685
This commit is contained in:
parent
eeaf779411
commit
1477c7ec1b
|
@ -215,12 +215,15 @@
|
|||
(list " ")))
|
||||
|
||||
(define-syntax (schemedefinput* stx)
|
||||
(syntax-case stx (eval-example-string define define-struct)
|
||||
(syntax-case stx (eval-example-string define define-values define-struct)
|
||||
[(_ (eval-example-string s))
|
||||
#'(schemeinput* (eval-example-string s))]
|
||||
[(_ (define . rest))
|
||||
(syntax-case stx ()
|
||||
[(_ e) #'(schemeblock+line e)])]
|
||||
[(_ (define-values . rest))
|
||||
(syntax-case stx ()
|
||||
[(_ e) #'(schemeblock+line e)])]
|
||||
[(_ (define-struct . rest))
|
||||
(syntax-case stx ()
|
||||
[(_ e) #'(schemeblock+line e)])]
|
||||
|
|
|
@ -213,7 +213,7 @@
|
|||
(*defstruct 'name 'fields (lambda () (list desc ...)))]))
|
||||
(define-syntax (defform*/subs stx)
|
||||
(syntax-case stx ()
|
||||
[(_ [spec spec1 ...] ([non-term-id non-term-form ...] ...) desc ...)
|
||||
[(_ #:literals (lit ...) [spec spec1 ...] ([non-term-id non-term-form ...] ...) desc ...)
|
||||
(with-syntax ([new-spec
|
||||
(syntax-case #'spec ()
|
||||
[(name . rest)
|
||||
|
@ -224,7 +224,7 @@
|
|||
#'name)
|
||||
#'rest)
|
||||
#'spec)])])
|
||||
#'(*defforms #t
|
||||
#'(*defforms #t '(lit ...)
|
||||
'(spec spec1 ...)
|
||||
(list (lambda (x) (schemeblock0 new-spec))
|
||||
(lambda (ignored) (schemeblock0 spec1)) ...)
|
||||
|
@ -233,7 +233,9 @@
|
|||
(lambda () (schemeblock0 non-term-form))
|
||||
...)
|
||||
...)
|
||||
(lambda () (list desc ...))))]))
|
||||
(lambda () (list desc ...))))]
|
||||
[(fm [spec spec1 ...] ([non-term-id non-term-form ...] ...) desc ...)
|
||||
#'(fm #:literals () [spec spec1 ...] ([non-term-id non-term-form ...] ...) desc ...)]))
|
||||
(define-syntax (defform* stx)
|
||||
(syntax-case stx ()
|
||||
[(_ [spec ...] desc ...) #'(defform*/subs [spec ...] () desc ...)]))
|
||||
|
@ -242,41 +244,49 @@
|
|||
[(_ spec desc ...) #'(defform*/subs [spec] () desc ...)]))
|
||||
(define-syntax (defform/subs stx)
|
||||
(syntax-case stx ()
|
||||
[(_ #:literals lits spec subs desc ...) #'(defform*/subs #:literals lits [spec] subs desc ...)]
|
||||
[(_ spec subs desc ...) #'(defform*/subs [spec] subs desc ...)]))
|
||||
(define-syntax (defform/none stx)
|
||||
(syntax-case stx ()
|
||||
[(_ spec desc ...)
|
||||
#'(*defforms #f
|
||||
#'(*defforms #f null
|
||||
'(spec) (list (lambda (ignored) (schemeblock0 spec)))
|
||||
null null
|
||||
(lambda () (list desc ...)))]))
|
||||
(define-syntax specsubform
|
||||
(syntax-rules ()
|
||||
[(_ #:literals (lit ...) spec desc ...)
|
||||
(*specsubform 'spec #f '(lit ...) (lambda () (schemeblock0 spec)) null null (lambda () (list desc ...)))]
|
||||
[(_ spec desc ...)
|
||||
(*specsubform 'spec #f (lambda () (schemeblock0 spec)) null null (lambda () (list desc ...)))]))
|
||||
(*specsubform 'spec #f null (lambda () (schemeblock0 spec)) null null (lambda () (list desc ...)))]))
|
||||
(define-syntax specspecsubform
|
||||
(syntax-rules ()
|
||||
[(_ spec desc ...)
|
||||
(make-blockquote "leftindent" (list (specsubform spec desc ...)))]))
|
||||
(define-syntax specform
|
||||
(syntax-rules ()
|
||||
[(_ #:literals (lit ...) spec desc ...)
|
||||
(*specsubform 'spec #t '(lit ...) (lambda () (schemeblock0 spec)) null null (lambda () (list desc ...)))]
|
||||
[(_ spec desc ...)
|
||||
(*specsubform 'spec #t (lambda () (schemeblock0 spec)) null null (lambda () (list desc ...)))]))
|
||||
(*specsubform 'spec #t null (lambda () (schemeblock0 spec)) null null (lambda () (list desc ...)))]))
|
||||
(define-syntax specform/subs
|
||||
(syntax-rules ()
|
||||
[(_ spec ([non-term-id non-term-form ...] ...) desc ...)
|
||||
[(_ #:literals (lit ...) spec ([non-term-id non-term-form ...] ...) desc ...)
|
||||
(*specsubform 'spec #t
|
||||
'(lit ...)
|
||||
(lambda () (schemeblock0 spec))
|
||||
'((non-term-id non-term-form ...) ...)
|
||||
(list (list (lambda () (scheme non-term-id))
|
||||
(lambda () (schemeblock0 non-term-form))
|
||||
...)
|
||||
...)
|
||||
(lambda () (list desc ...)))]))
|
||||
(lambda () (list desc ...)))]
|
||||
[(_ spec ([non-term-id non-term-form ...] ...) desc ...)
|
||||
(specform/subs #:literals () spec ([non-term-id non-term-form ...] ...) desc ...)]))
|
||||
(define-syntax specsubform/inline
|
||||
(syntax-rules ()
|
||||
[(_ spec desc ...)
|
||||
(*specsubform 'spec #f #f null null (lambda () (list desc ...)))]))
|
||||
(*specsubform 'spec #f null #f null null (lambda () (list desc ...)))]))
|
||||
(define-syntax defthing
|
||||
(syntax-rules ()
|
||||
[(_ id result desc ...)
|
||||
|
@ -495,7 +505,7 @@
|
|||
|
||||
(define (meta-symbol? s) (memq s '(... ...+ ?)))
|
||||
|
||||
(define (*defforms kw? forms form-procs subs sub-procs content-thunk)
|
||||
(define (*defforms kw? lits forms form-procs subs sub-procs content-thunk)
|
||||
(parameterize ([current-variable-list
|
||||
(apply
|
||||
append
|
||||
|
@ -503,7 +513,8 @@
|
|||
(let loop ([form (cons (if kw? (cdr form) form)
|
||||
subs)])
|
||||
(cond
|
||||
[(symbol? form) (if (meta-symbol? form)
|
||||
[(symbol? form) (if (or (meta-symbol? form)
|
||||
(memq form lits))
|
||||
null
|
||||
(list form))]
|
||||
[(pair? form) (append (loop (car form))
|
||||
|
@ -543,12 +554,13 @@
|
|||
sub-procs))))
|
||||
(content-thunk)))))
|
||||
|
||||
(define (*specsubform form has-kw? form-thunk subs sub-procs content-thunk)
|
||||
(define (*specsubform form has-kw? lits form-thunk subs sub-procs content-thunk)
|
||||
(parameterize ([current-variable-list
|
||||
(append (let loop ([form (cons (if has-kw? (cdr form) form)
|
||||
subs)])
|
||||
(cond
|
||||
[(symbol? form) (if (meta-symbol? form)
|
||||
[(symbol? form) (if (or (meta-symbol? form)
|
||||
(memq form lits))
|
||||
null
|
||||
(list form))]
|
||||
[(pair? form) (append (loop (car form))
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
;; This is temporary, until the MzScheme manual is filled in...
|
||||
(make-parameter '(define require provide
|
||||
define-values begin0 when unless
|
||||
new send if cond begin else and or
|
||||
new send if cond begin else => and or
|
||||
define-syntax syntax-rules define-struct
|
||||
quote quasiquote unquote unquote-splicing
|
||||
syntax quasisyntax unsyntax unsyntax-splicing
|
||||
|
@ -377,14 +377,14 @@
|
|||
value-color]
|
||||
[(identifier? c)
|
||||
(cond
|
||||
[is-var?
|
||||
variable-color]
|
||||
[(and (identifier? c)
|
||||
(memq (syntax-e c) (current-keyword-list)))
|
||||
keyword-color]
|
||||
[(and (identifier? c)
|
||||
(memq (syntax-e c) (current-meta-list)))
|
||||
meta-color]
|
||||
[is-var?
|
||||
variable-color]
|
||||
[it? variable-color]
|
||||
[else symbol-color])]
|
||||
[else paren-color])
|
||||
|
|
|
@ -20,7 +20,7 @@ bound as a syntax transformer (such as @scheme[if] or
|
|||
|
||||
A function call is evaluated by first evaluating the
|
||||
@scheme[_proc-expr] and all @scheme[_arg-expr]s in order (left to
|
||||
right). Then, if @scheme[_proc-expr] produced a function that accepts
|
||||
right). Then, if @scheme[_proc-expr] produces a function that accepts
|
||||
as many arguments as supplied @scheme[_arg-expr]s, the function is
|
||||
called. Otherwise, an exception is raised.
|
||||
|
||||
|
@ -32,11 +32,11 @@ called. Otherwise, an exception is raised.
|
|||
]
|
||||
|
||||
Some functions, such as @scheme[cons], accept a fixed number of
|
||||
arguments. Some functions, such as @scheme[list], accept any number
|
||||
of arguments. Some functions accept a range of argument counts; for
|
||||
example @scheme[substring] accepts either two or three arguments. A
|
||||
function's @idefterm{arity} is the number of arguments that it
|
||||
accepts.
|
||||
arguments. Some functions, such as @scheme[+] or @scheme[list], accept
|
||||
any number of arguments. Some functions accept a range of argument
|
||||
counts; for example @scheme[substring] accepts either two or three
|
||||
arguments. A function's @idefterm{arity} is the number of arguments
|
||||
that it accepts.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "guide:keyword-args"]{Keyword Arguments}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
@require[(lib "eval.ss" "scribble")]
|
||||
@require["guide-utils.ss"]
|
||||
|
||||
@title{Identifiers and Binding}
|
||||
@title[#:tag "guide:binding"]{Identifiers and Binding}
|
||||
|
||||
The context of an expression determines the meaning of identifiers
|
||||
that appear in the expression. In particular, starting a module with
|
||||
|
@ -12,7 +12,7 @@ the language @schememodname[big], as in
|
|||
@schememod[big]
|
||||
|
||||
means that, within the module, the identifiers described in this guide
|
||||
have the the meaning described here: @scheme[cons] refers to the
|
||||
start with the meaning described here: @scheme[cons] refers to the
|
||||
function that creates a pair, @scheme[car] refers to the function
|
||||
that extracts the first element of a pair, and so on.
|
||||
|
||||
|
@ -21,7 +21,7 @@ that extracts the first element of a pair, and so on.
|
|||
|
||||
Forms like @scheme[define], @scheme[lambda], and @scheme[let]
|
||||
associate a meaning with one or more identifiers; that is, they
|
||||
@defterm{bind} identifier. The part of the program for which the
|
||||
@defterm{bind} identifiers. The part of the program for which the
|
||||
binding applies is the @defterm{scope} of the binding. The set of
|
||||
bindings in effect for a given expression is the expression's
|
||||
@defterm{environment}.
|
||||
|
@ -67,7 +67,7 @@ existing binding.
|
|||
|
||||
Even identifiers like @scheme[define] and @scheme[lambda] get their
|
||||
meanings from bindings, though they have @defterm{transformer}
|
||||
bindings (whcih means that they define syntactic forms) instead of
|
||||
bindings (which means that they indicate syntactic forms) instead of
|
||||
value bindings. Since @scheme[define] has a transformer binding, the
|
||||
identifier @schemeidfont{define} cannot be used by itself to get a
|
||||
value. However, the normal binding for @schemeidfont{define} can be
|
||||
|
|
163
collects/scribblings/guide/cond.scrbl
Normal file
163
collects/scribblings/guide/cond.scrbl
Normal file
|
@ -0,0 +1,163 @@
|
|||
#reader(lib "docreader.ss" "scribble")
|
||||
@require[(lib "manual.ss" "scribble")]
|
||||
@require[(lib "eval.ss" "scribble")]
|
||||
@require["guide-utils.ss"]
|
||||
|
||||
@title{Conditionals}
|
||||
|
||||
Most functions used for branching, such as @scheme[<] and
|
||||
@scheme[string?], produce either @scheme[#t] or @scheme[#f]. Scheme's
|
||||
branching forms, however, treat any value other than @scheme[#f] as
|
||||
true. We we say a @defterm{true value} to mean any value other than
|
||||
@scheme[#f].
|
||||
|
||||
This convention for ``true value'' meshes well with protocols where
|
||||
@scheme[#f] can serve as failure or to indicate that an optional value
|
||||
is not supplied. (Beware of overusing this trick, and remember that an
|
||||
exception is usually a better mechanism to report failure.)
|
||||
|
||||
For example, the @scheme[member] function serves double duty; it can
|
||||
be used to find the tail of a list that starts with a particular item,
|
||||
or it can be used to simply check whether an item is present in a
|
||||
list:
|
||||
|
||||
@interaction[
|
||||
(member "Groucho" '("Harpo" "Zeppo"))
|
||||
(member "Groucho" '("Harpo" "Groucho" "Zeppo"))
|
||||
(if (member "Groucho" '("Harpo" "Zeppo"))
|
||||
'yep
|
||||
'nope)
|
||||
(if (member "Groucho" '("Harpo" "Groucho" "Zeppo"))
|
||||
'yep
|
||||
'nope)
|
||||
]
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Simple Branching: @scheme[if]}
|
||||
|
||||
In an @scheme[if] form,
|
||||
|
||||
@specform[(if test-expr then-expr else-expr)]
|
||||
|
||||
the @scheme[_test-expr] is always evaluated. If it produces any value
|
||||
other than @scheme[#f], then @scheme[_then-expr] is
|
||||
evaluated. Otherwise, @scheme[_else-expr] is evaluated.
|
||||
|
||||
An @scheme[if] form must have both an @scheme[_then-expr] and an
|
||||
@scheme[_else-expr]; the latter is not optional. To perform (or skip)
|
||||
side-effects based on a @scheme[_test-expr], use @scheme[when] or
|
||||
@scheme[unless], which we describe later in @secref["guide:begin"].
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Combining Tests: @scheme[and] and @scheme[or]}
|
||||
|
||||
Scheme's @scheme[and] and @scheme[or] are syntactic forms, rather than
|
||||
functions. Unlike a function, the @scheme[and] and @scheme[or] forms
|
||||
can skip evaluation of later expressions if an earlier one determines
|
||||
the answer.
|
||||
|
||||
@specform[(and expr ...)]
|
||||
|
||||
An @scheme[or] form produces @scheme[#f] if any of its @scheme[expr]s
|
||||
produces @scheme[#f]. Otherwise, it produces the value of its last
|
||||
@scheme[_expr]. As a special case, @scheme[(and)] produces
|
||||
@scheme[#t].
|
||||
|
||||
@specform[(or expr ...)]
|
||||
|
||||
The @scheme[and] form produces @scheme[#f] if any of its
|
||||
@scheme[_expr]s produces @scheme[#f]. Otherwise, it produces the first
|
||||
non-@scheme[#f] value from its @scheme[expr]s. As a special case,
|
||||
@scheme[(or)] produces @scheme[#f].
|
||||
|
||||
@examples[
|
||||
(code:line
|
||||
(define (got-milk? lst)
|
||||
(and (not (null? lst))
|
||||
(or (eq? 'milk (car lst))
|
||||
(got-milk? (cdr lst))))) (code:comment #, @t{recurs only if needed}))
|
||||
(got-milk? '(apple banana))
|
||||
(got-milk? '(apple milk banana))
|
||||
]
|
||||
|
||||
If evaluation reaches the last @scheme[_expr] of an @scheme[and] or
|
||||
@scheme[or] form, then the @scheme[_expr]'s value directly determines
|
||||
the @scheme[and] or @scheme[or] result. Therefore, the last
|
||||
@scheme[expr] is in tail position, which means that the above
|
||||
@scheme[got-milk?] function runs in constant space.
|
||||
|
||||
@margin-note{For an introduction to tail calls and tail positions, see
|
||||
@secref["guide:tail-recursion"].}
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Chaining Tests: @scheme[cond]}
|
||||
|
||||
The @scheme[cond] form chains a series of tests to select a result
|
||||
expression. To a first approximation, the syntax of @scheme[cond] is
|
||||
as follows:
|
||||
|
||||
@specform[(cond [test-expr expr ...+]
|
||||
...)]
|
||||
|
||||
Each @scheme[_test-expr] is evaluated in order. If it produces
|
||||
@scheme[#f], the corresponding @scheme[_expr]s are ignored, and
|
||||
evaluation proceeds to the next @scheme[_test-expr]. As soon as a
|
||||
@scheme[_test-expr] produces a true value, its @scheme[_text-expr]s
|
||||
are evaluated to produce the result for the @scheme[cond] form, and no
|
||||
further @scheme[_test-expr]s are evaluated.
|
||||
|
||||
The last @scheme[_test-expr] in a @scheme[cond] can be replaced by
|
||||
@scheme[else]. In terms of evaluation, @scheme[else] serves as a
|
||||
synonym for @scheme[#t], but it clarifies that the last clause is
|
||||
meant to catch all remaining cases. If @scheme[else] is not used, then
|
||||
it is possible that no @scheme[_test-expr]s produce a true value; in
|
||||
that case, the result of the @scheme[cond] expression is
|
||||
@|void-const|.
|
||||
|
||||
@examples[
|
||||
(cond
|
||||
[(= 2 3) (error "wrong!")]
|
||||
[(= 2 2) 'ok])
|
||||
(cond
|
||||
[(= 2 3) (error "wrong!")])
|
||||
(cond
|
||||
[(= 2 3) (error "wrong!")]
|
||||
[else 'ok])
|
||||
]
|
||||
|
||||
@def+int[
|
||||
(define (got-milk? lst)
|
||||
(cond
|
||||
[(null? lst) #f]
|
||||
[(eq? 'milk (car lst)) #t]
|
||||
[else (got-milk? (cdr lst))]))
|
||||
(got-milk? '(apple banana))
|
||||
(got-milk? '(apple milk banana))
|
||||
]
|
||||
|
||||
The full syntax of @scheme[cond] includes two more kinds of clauses:
|
||||
|
||||
@specform/subs[#:literals (else =>)
|
||||
(cond cond-clause ...)
|
||||
([cond-clause [test-expr then-expr ...+]
|
||||
[else then-expr ...+]
|
||||
[test-expr => proc-expr]
|
||||
[test-expr]])]
|
||||
|
||||
The @scheme[=>] variant captures the true result of its
|
||||
@scheme[_test-expr] and passes it to the result of the
|
||||
@scheme[_proc-expr], which must be a function of one argument.
|
||||
|
||||
@examples[
|
||||
(define (after-groucho lst)
|
||||
(cond
|
||||
[(member "Groucho" lst) => cdr]
|
||||
[else (error "not there")]))
|
||||
|
||||
(after-groucho '("Harpo" "Groucho" "Zeppo"))
|
||||
(after-groucho '("Harpo" "Zeppo"))
|
||||
]
|
||||
|
||||
A clause that includes only a @scheme[_test-expr] is rarely used. It
|
||||
captures the true result of the @scheme[_test-expr], and simply
|
||||
returns the result for the whole @scheme[cond] expression.
|
|
@ -30,7 +30,7 @@ definitions:
|
|||
which is a shorthand for
|
||||
|
||||
@schemeblock[
|
||||
(define id (lambda (arg ...) _body ...+))
|
||||
(define _id (lambda (_arg ...) _body ...+))
|
||||
]
|
||||
|
||||
@defexamples[
|
||||
|
@ -51,12 +51,12 @@ The function shorthand via @scheme[define] also supports a ``rest''
|
|||
argument (i.e., a final argument to collect extra arguments in a
|
||||
list):
|
||||
|
||||
@specform[(define (id arg ... . rest-id) expr)]{}
|
||||
@specform[(define (id arg ... . rest-id) body ...+)]{}
|
||||
|
||||
which is a shorthand
|
||||
|
||||
@schemeblock[
|
||||
(define id (lambda (id arg ... . rest-id) body-expr ...+))
|
||||
(define _id (lambda (_arg ... . _rest-id) _body ...+))
|
||||
]
|
||||
|
||||
@defexamples[
|
||||
|
@ -69,22 +69,25 @@ which is a shorthand
|
|||
@section{Curried Function Shorthand}
|
||||
|
||||
Consider the following @scheme[make-add-suffix] function that takes a
|
||||
string and returns another function that takes a string. Normally, the
|
||||
result of @scheme[make-add-suffix] would be sent to some other
|
||||
function, but it could be called directly, like this:
|
||||
string and returns another function that takes a string:
|
||||
|
||||
@def+int[
|
||||
(define make-add-suffix
|
||||
(lambda (s2)
|
||||
(lambda (s) (string-append s s2))))
|
||||
]
|
||||
|
||||
Although it's not common, result of @scheme[make-add-suffix] could be
|
||||
called directly, like this:
|
||||
|
||||
@interaction[
|
||||
((make-add-suffix "!") "hello")
|
||||
]
|
||||
|
||||
In a sense, the @scheme[make-add-suffix] function takes two arguments,
|
||||
but it takes them one at a time. A function that takes some of its
|
||||
arguments and returns a function to consume more is sometimes called a
|
||||
@defterm{curried function}.
|
||||
In a sense, @scheme[make-add-suffix] is a function takes two
|
||||
arguments, but it takes them one at a time. A function that takes some
|
||||
of its arguments and returns a function to consume more is sometimes
|
||||
called a @defterm{curried function}.
|
||||
|
||||
Using the function-shorthand form of @scheme[define],
|
||||
@scheme[make-add-suffix] can be written equivalently as
|
||||
|
@ -236,7 +239,7 @@ the result is a special value @|undefined-const|.
|
|||
A sequence of internal definitions using just @scheme[define] is
|
||||
easily translated to an equivalent @scheme[letrec] form (as introduced
|
||||
in the next section). However, other definition forms can appear as a
|
||||
@scheme[_body], including @scheme[define-struct] (see
|
||||
@scheme[_body], including @scheme[define-values], @scheme[define-struct] (see
|
||||
@secref["guide:define-struct"]) or @scheme[define-syntax] (see
|
||||
@secref["guide:macros"]).
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ convention implicitly defines the meaning of many meta-variables:
|
|||
|
||||
Square brackets in the grammar indicate a parenthesized sequence of
|
||||
forms, where square brackets are normally used (by convention). That
|
||||
is square brackets @italic{do not} mean optional parts of the
|
||||
is, square brackets @italic{do not} mean optional parts of the
|
||||
syntactic form.
|
||||
|
||||
A @schememetafont{...} indicates zero or more repetitions of the
|
||||
|
@ -56,7 +56,7 @@ preceding form, and @schememetafont{...+} indicates one or more
|
|||
repetitions of the preceding datum. Otherwise, non-italicized
|
||||
identifiers stand form themselves.
|
||||
|
||||
Based on the above grammar, then, here are a few legal uses of
|
||||
Based on the above grammar, then, here are a few conforming uses of
|
||||
@schemekeywordfont{something}:
|
||||
|
||||
@schemeblock[
|
||||
|
@ -65,9 +65,10 @@ Based on the above grammar, then, here are a few legal uses of
|
|||
(#,(schemekeywordfont "something") [x my-favorite-martian x] (+ 1 2) #f)
|
||||
]
|
||||
|
||||
Some syntactic forms refer to meta-variables that are not implicitly
|
||||
defined and not previously defined. Such meta-variables are defined
|
||||
using a BNF-like format for alternatives:
|
||||
Some syntactic-form specifications refer to meta-variables that are
|
||||
not implicitly defined and not previously defined. Such meta-variables
|
||||
are defined after the main form, using a BNF-like format for
|
||||
alternatives:
|
||||
|
||||
@specform/subs[(#,(schemekeywordfont "something-else") [thing ...+] an-expr ...)
|
||||
([thing thing-id
|
||||
|
@ -83,11 +84,9 @@ form, a @scheme[_thing] is either an identifier or a keyword.
|
|||
@include-section["lambda.scrbl"]
|
||||
@include-section["define.scrbl"]
|
||||
@include-section["let.scrbl"]
|
||||
@include-section["named-let.scrbl"]
|
||||
@include-section["cond.scrbl"]
|
||||
|
||||
@section{Conditionals: @scheme[if], @scheme[cond], @scheme[and], and @scheme[or]}
|
||||
|
||||
@section{Sequencing: @scheme[begin], @scheme[begin0], @scheme[when], and @scheme[unless]}
|
||||
@section[#:tag "guide:begin"]{Sequencing: @scheme[begin], @scheme[begin0], @scheme[when], and @scheme[unless]}
|
||||
|
||||
@section{Assignment: @scheme[set!]}
|
||||
|
||||
|
|
|
@ -99,6 +99,13 @@ using @idefterm{contracts}.
|
|||
@; ----------------------------------------------------------------------
|
||||
@section[#:tag "performance"]{Performance}
|
||||
|
||||
Every definition or expression is compiled to an internal bytecode
|
||||
format. Standard optimizations are applied when compiling the
|
||||
bytecode. For example, in an environment where when @scheme[+] has its
|
||||
usual binding, the expression @scheme[(let ([x 1][y (lambda () 4)]) (+
|
||||
1 (y)))] is compiled the same as the constant @scheme[5] due to
|
||||
constant propagation, constant folding, and inlining optimizations.
|
||||
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
@section[#:tag "ffi"]{Foreign-Function Interface@aux-elem{ (FFI)}}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
@title[#:tag "guide:lambda"]{Functions@aux-elem{ (Procedures)}: @scheme[lambda]}
|
||||
|
||||
Such a @scheme[lambda] expression creates a function. In the simplest
|
||||
A @scheme[lambda] expression creates a function. In the simplest
|
||||
case, a @scheme[lambda] expression has the form
|
||||
|
||||
@specform[
|
||||
|
@ -180,11 +180,11 @@ specifies a keyword-based argument with a default value.
|
|||
|
||||
The @scheme[lambda] form does not directly support the creation
|
||||
of a function that accepts ``rest'' keywords. To construct a
|
||||
function that accepts any and all keyword arguments, use
|
||||
function that accepts all keyword arguments, use
|
||||
@scheme[make-keyword-procedure]. The function supplied to
|
||||
@scheme[make-keyword-procedure] receives keyword arguments through
|
||||
parallel lists in the first two (by-position) arguments, and
|
||||
then all by-position arguments from an application as the
|
||||
@scheme[make-keyword-procedure] receives keyword arguments
|
||||
through parallel lists in the first two (by-position) arguments,
|
||||
and then all by-position arguments from an application as the
|
||||
remaining by-position arguments.
|
||||
|
||||
@margin-note{For an introduction to @scheme[keyword-apply], see
|
||||
|
|
|
@ -3,5 +3,183 @@
|
|||
@require[(lib "eval.ss" "scribble")]
|
||||
@require["guide-utils.ss"]
|
||||
|
||||
@title{Local Binding: @scheme[let], @scheme[let*], and @scheme[letrec]}
|
||||
@interaction-eval[(require (lib "file.ss"))]
|
||||
|
||||
@title{Local Binding}
|
||||
|
||||
Although internal @scheme[define]s can be used for local binding,
|
||||
Scheme provides three forms that give the programmer more
|
||||
control over bindings: @scheme[let], @scheme[let*], and
|
||||
@scheme[letrec].
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Parallel Binding: @scheme[let]}
|
||||
|
||||
A @scheme[let] form binds a set of identifiers, each to the result of
|
||||
some expression, for use in the @scheme[let] body:
|
||||
|
||||
@specform[(let ([id expr] ...) body ...+)]{}
|
||||
|
||||
The @scheme[_id]s are bound ``in parallel.'' That is, no @scheme[_id]
|
||||
is bound in the right-hand side @scheme[_expr] for any @scheme[_id],
|
||||
but all are available in the @scheme[_body]. The @scheme[_id]s must be
|
||||
different from each other.
|
||||
|
||||
@examples[
|
||||
(let ([me "Bob"])
|
||||
me)
|
||||
(let ([me "Bob"]
|
||||
[myself "Robert"]
|
||||
[I "Bobby"])
|
||||
(list me myself I))
|
||||
(let ([me "Bob"]
|
||||
[me "Robert"])
|
||||
me)
|
||||
]
|
||||
|
||||
The fact that an @scheme[_id]'s @scheme[_expr] does not see its own
|
||||
binding is often useful for wrappers that must refer back to the old
|
||||
value:
|
||||
|
||||
@interaction[
|
||||
(let ([+ (lambda (x y)
|
||||
(if (string? x)
|
||||
(string-append x y)
|
||||
(+ x y)))]) (code:comment #, @t{use original @scheme[+]})
|
||||
(list (+ 1 2)
|
||||
(+ "see" "saw")))
|
||||
]
|
||||
|
||||
Occasionally, the parallel nature of @scheme[let] bindings is
|
||||
convenient for swapping or rearranging a set of bindings:
|
||||
|
||||
@interaction[
|
||||
(let ([me "Tarzan"]
|
||||
[you "Jane"])
|
||||
(let ([me you]
|
||||
[you me])
|
||||
(list me you)))
|
||||
]
|
||||
|
||||
The characterization of @scheme[let] bindings as ``parallel'' is not
|
||||
meant to imply concurrent evaluation. The @scheme[_expr]s are
|
||||
evaluated in order, even though the bindings are delayed until all
|
||||
@scheme[_expr]s are evaluated.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Sequential Binding: @scheme[let*]}
|
||||
|
||||
The syntax of @scheme[let*] is the same as @scheme[let]:
|
||||
|
||||
@specform[(let* ([id expr] ...) body ...+)]{}
|
||||
|
||||
The difference is that each @scheme[_id] is available for use in later
|
||||
@scheme[_expr]s, as well as in the @scheme[_body]. Furthermore, the
|
||||
@scheme[_id]s need not be distinct, and the most recent binding is the
|
||||
visible one.
|
||||
|
||||
@examples[
|
||||
(let* ([x (list "Borroughs")]
|
||||
[y (cons "Rice" x)]
|
||||
[z (cons "Edgar" y)])
|
||||
(list x y z))
|
||||
(let* ([name (list "Borroughs")]
|
||||
[name (cons "Rice" name)]
|
||||
[name (cons "Edgar" name)])
|
||||
name)
|
||||
]
|
||||
|
||||
In other words, a @scheme[let*] form is equivalent to nested
|
||||
@scheme[let] forms, each with a single binding:
|
||||
|
||||
@interaction[
|
||||
(let ([name (list "Borroughs")])
|
||||
(let ([name (cons "Rice" name)])
|
||||
(let ([name (cons "Edgar" name)])
|
||||
name)))
|
||||
]
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Recursive Binding: @scheme[letrec]}
|
||||
|
||||
The syntax of @scheme[letrec] is also the same as @scheme[let]:
|
||||
|
||||
@specform[(letrec ([id expr] ...) body ...+)]{}
|
||||
|
||||
While @scheme[let] makes its bindings available only in the
|
||||
@scheme[_body]s, and @scheme[let*] makes its bindings available to any
|
||||
later binding @scheme[_expr], @scheme[letrec] makes its bindings
|
||||
available to all other @scheme[_expr]s---even earlier ones. In other
|
||||
words, @scheme[letrec] bindings are recursive.
|
||||
|
||||
The @scheme[_expr]s in a @scheme[letrec] form are most often
|
||||
@scheme[lambda] forms for recursive and mutually recursive functions:
|
||||
|
||||
@interaction[
|
||||
(letrec ([swing
|
||||
(lambda (t)
|
||||
(if (eq? (car t) 'tarzan)
|
||||
(cons 'vine
|
||||
(cons 'tarzan (cddr t)))
|
||||
(cons (car t)
|
||||
(swing (cdr t)))))])
|
||||
(swing '(vine tarzan vine vine)))
|
||||
]
|
||||
|
||||
@interaction[
|
||||
(letrec ([tarzan-in-tree?
|
||||
(lambda (name path)
|
||||
(or (equal? name "tarzan")
|
||||
(and (directory-exists? path)
|
||||
(tarzan-in-directory? path))))]
|
||||
[tarzan-in-directory?
|
||||
(lambda (dir)
|
||||
(ormap (lambda (elem)
|
||||
(tarzan-in-tree? (path-element->string elem)
|
||||
(build-path dir elem)))
|
||||
(directory-list dir)))])
|
||||
(tarzan-in-tree? "tmp" (find-system-path 'temp-dir)))
|
||||
]
|
||||
|
||||
While the @scheme[_expr]s of a @scheme[letrec] form are typically
|
||||
@scheme[lambda] expressions, they can be any expression. The
|
||||
expressions are evaluated in order, and after each value is obtained,
|
||||
it is immediately associated with its corresponding @scheme[_id]. If
|
||||
an @scheme[_id] is referenced before its value is ready, the result is
|
||||
@|undefined-const|, as just as for internal definitions.
|
||||
|
||||
@interaction[
|
||||
(letrec ([quicksand quicksand])
|
||||
quicksand)
|
||||
]
|
||||
|
||||
@; ----------------------------------------
|
||||
@include-section["named-let.scrbl"]
|
||||
|
||||
@; ----------------------------------------
|
||||
@section{Multiple Values: @scheme[let-values], @scheme[let*-values], and @scheme[letrec-values]}
|
||||
|
||||
In the same way that @scheme[define-values] binds multiple
|
||||
results in a definition (see @secref["guide:multiple-values"]),
|
||||
@scheme[let-values], @scheme[let*-values], and
|
||||
@scheme[letrec-values] bind multiple results locally.
|
||||
|
||||
@specform[(let-values ([(id ...) expr] ...)
|
||||
body ...+)]
|
||||
@specform[(let*-values ([(id ...) expr] ...)
|
||||
body ...+)]
|
||||
@specform[(letrec-values ([(id ...) expr] ...)
|
||||
body ...+)]
|
||||
|
||||
Each @scheme[_expr] must produce as many values as coresponding
|
||||
@scheme[_id]s. The binding rules are the same for the forms
|
||||
without @schemekeywordfont{-values} forms: the @scheme[_id]s of
|
||||
@scheme[let-values] are bound only in the @scheme[_body]s, the
|
||||
@scheme[_id]s of @scheme[let*-values]s are bound in
|
||||
@scheme[_expr]s of later clauses, and the @scheme[_id]s of
|
||||
@scheme[letrec-value]s are bound for all @scheme[_expr]s.
|
||||
|
||||
@examples[
|
||||
(let-values ([(q r) (quotient/remainder 14 3)])
|
||||
(list q r))
|
||||
]
|
||||
|
|
|
@ -182,6 +182,9 @@ If the derivation of the above definitions is mysterious to you,
|
|||
consider reading @|HtDP|. If you are merely suspicious of the use
|
||||
of recursive calls instead of a looping construct, then read on.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "guide:tail-recursion"]{Tail Recursion}
|
||||
|
||||
Both the @scheme[my-length] and @scheme[my-map] functions run in
|
||||
@math{O(n)} time for a list of length @math{n}. This is easy to see by
|
||||
imagining how @scheme[(my-length (list "a" "b" "c"))] must evaluate:
|
||||
|
@ -238,7 +241,10 @@ one, because that takes up space for no good reason.
|
|||
|
||||
This evaluation behavior is sometimes called @idefterm{tail-call
|
||||
optimization}, but it's not merely an ``optimization'' in Scheme; it's
|
||||
a guarantee about the way the code will run.
|
||||
a guarantee about the way the code will run. More precisely, an
|
||||
expression in @idefterm{tail position} with respect to another
|
||||
expression does not take extra computation space over the other
|
||||
expression.
|
||||
|
||||
In the case of @scheme[my-map], @math{O(n)} space complexity is
|
||||
reasonable, since it has to generate a result of size
|
||||
|
|
|
@ -10,18 +10,16 @@ same syntactic keyword @scheme[let] as for local binding, but an
|
|||
identifier after the @scheme[let] (instead of an immediate open
|
||||
parenthesis) triggers a different parsing.
|
||||
|
||||
In general,
|
||||
|
||||
@schemeblock[
|
||||
@specform[
|
||||
(let _proc-id ([_arg-id _init-expr] ...)
|
||||
_body-expr ...+)
|
||||
_body ...+)
|
||||
]
|
||||
|
||||
is equivalent to
|
||||
A named @scheme[let] form is equivalent to
|
||||
|
||||
@schemeblock[
|
||||
(letrec ([_proc-id (lambda (_arg-id ...)
|
||||
_body-expr ...+)])
|
||||
_body ...+)])
|
||||
(_proc-id _init-expr ...))
|
||||
]
|
||||
|
||||
|
|
31
collects/scribblings/guide/ports.scrbl
Normal file
31
collects/scribblings/guide/ports.scrbl
Normal file
|
@ -0,0 +1,31 @@
|
|||
#reader(lib "docreader.ss" "scribble")
|
||||
@require[(lib "manual.ss" "scribble")]
|
||||
@require[(lib "eval.ss" "scribble")]
|
||||
@require["guide-utils.ss"]
|
||||
|
||||
@title[#:tag "ports"]{Input and Output Ports}
|
||||
|
||||
A @defterm{port} encapsulates an I/O stream, normally for just one
|
||||
direction. An @defterm{input port} reads from a stream, and an
|
||||
@defterm{output port} writes to a string.
|
||||
|
||||
For many procedures that accept a port argument, the argument is
|
||||
optional, and it defaults to either the @defterm{current input port}
|
||||
or @defterm{current output port}. For @exec{mzscheme}, the current
|
||||
ports are initialized to the process's stdin and stdout. The
|
||||
@scheme[current-input-port] and @scheme[current-output-port]
|
||||
procedures, whien called with no arguments, return the current output
|
||||
and input port, respectively.
|
||||
|
||||
@examples[
|
||||
(display "hello world\n")
|
||||
(display "hello world\n" (current-output-port))
|
||||
]
|
||||
|
||||
Ports are created by various procedures that specific to the different
|
||||
kinds of streams. For example, @scheme[open-input-file] creates an
|
||||
input port for reading from a file. Procedures like
|
||||
@scheme[with-input-from-file] both create a port and install it as the
|
||||
current port while calling a given body procedure.
|
||||
|
||||
See @secref["io"] for information about using ports.
|
|
@ -5,4 +5,143 @@
|
|||
|
||||
@local-table-of-contents[]
|
||||
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "mz:cond"]{Conditionals: @scheme[cond]}
|
||||
|
||||
@defform/subs[#:literals (else =>)
|
||||
(cond cond-clause ...)
|
||||
([cond-clause [test-expr then-expr ...+]
|
||||
[else then-expr ...+]
|
||||
[test-expr => proc-expr]
|
||||
[test-expr]])]{
|
||||
|
||||
A @scheme[cond-clause] that starts with @scheme[else] must be the last
|
||||
@scheme[cond-clause].
|
||||
|
||||
If no @scheme[cond-clause]s are present, the result is @|void-const|.
|
||||
|
||||
If only a @scheme[[else then-expr ...+]] is present, then the
|
||||
@scheme[then-expr]s are evaluated. The results from all but the last
|
||||
@scheme[then-expr] are ignored. The results of the last
|
||||
@scheme[then-expr], which is in tail position with respect to the
|
||||
@scheme[cond] form, provides the result for the whole @scheme[cond]
|
||||
form.
|
||||
|
||||
Otherwise, the first @scheme[test-expr] is evaluated. If it produces
|
||||
@scheme[#f], then the result is the same as a @scheme[cond] form with
|
||||
the remaining @scheme[cond-clause]s, in tail position with respect to
|
||||
the original @scheme[cond] form. Otherwise, evaluation depends on the
|
||||
form of the @scheme[cond-clause]:
|
||||
|
||||
@specsubform[[test-expr then-expr ...+]]{The @scheme[then-expr]s are
|
||||
evaluated in order, and the results from all but the last
|
||||
@scheme[then-expr] are ignored. The results of the last
|
||||
@scheme[then-expr], which is in tail position with respect to the
|
||||
@scheme[cond] form, provides the result for the whole @scheme[cond]
|
||||
form.}
|
||||
|
||||
@specsubform[#:literals (=>) [test-expr => proc-expr]]{The @scheme[proc-expr] is
|
||||
evaluated, and it must produce a procedure that accepts on argument,
|
||||
otherwise the @exnraise[exn:fail:contract]. The procedure is applied
|
||||
to the result of @scheme[test-expr] in tail position with respect to
|
||||
the @scheme[cond] expression.}
|
||||
|
||||
@specsubform[[test-expr]]{The result of the @scheme[test-expr] is
|
||||
returned as the result of the @scheme[cond] form. The
|
||||
@scheme[test-expr] is not in tail position.}
|
||||
|
||||
@examples[
|
||||
(cond)
|
||||
(cond
|
||||
[else 5])
|
||||
(cond
|
||||
[(positive? -5) (error "doesn't get here")]
|
||||
[(zero? -5) (error "doesn't get here, either")]
|
||||
[(positive? 5) 'here])
|
||||
(cond
|
||||
[(member 2 '(1 2 3)) => (lambda (l) (map - l))])
|
||||
(cond
|
||||
[(member 2 '(1 2 3))])
|
||||
]}
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Boolean Combination: @scheme[and] and @scheme[or]}
|
||||
|
||||
@defform[(and expr ...)]{
|
||||
|
||||
If no @scheme[expr]s are provided, then result is @scheme[#f].
|
||||
|
||||
If a single @scheme[expr] is provided, then it is in tail position, so
|
||||
the results of the @scheme[and] expression are the results of the
|
||||
@scheme[expr].
|
||||
|
||||
Otherwise, the first @scheme[expr] is evaluated. If it produces
|
||||
@scheme[#f], the result of the @scheme[and] expression is
|
||||
@scheme[#f]. Otherwise, the result is the same as an @scheme[and]
|
||||
expression with the remaining @scheme[expr]s in tail position with
|
||||
respect to the original @scheme[and] form.
|
||||
|
||||
@examples[
|
||||
(and)
|
||||
(and 1)
|
||||
(and (values 1 2))
|
||||
(and #f (error "doesn't get here"))
|
||||
(and #t 5)
|
||||
]}
|
||||
|
||||
@defform[(or expr ...)]{
|
||||
|
||||
If no @scheme[expr]s are provided, then result is @scheme[#t].
|
||||
|
||||
If a single @scheme[expr] is provided, then it is in tail position, so
|
||||
the results of the @scheme[and] expression are the results of the
|
||||
@scheme[expr].
|
||||
|
||||
Otherwise, the first @scheme[expr] is evaluated. If it produces a
|
||||
value other than @scheme[#f], that result is the result of the
|
||||
@scheme[or] expression. Otherwise, the result is the same as an
|
||||
@scheme[or] expression with the remaining @scheme[expr]s in tail
|
||||
position with respect to the original @scheme[or] form.
|
||||
|
||||
@examples[
|
||||
(or)
|
||||
(or 1)
|
||||
(or (values 1 2))
|
||||
(or 5 (error "doesn't get here"))
|
||||
(or #f 5)
|
||||
]}
|
||||
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Guarded Evaluation: @scheme[when] and @scheme[unless]}
|
||||
|
||||
@defform[(while test-expr expr ...)]{
|
||||
|
||||
Evaluates the @scheme[text-expr]. If the result is any value other
|
||||
than @scheme[#f], the @scheme[expr]s are evaluated, and the results
|
||||
are ignored. No @scheme[expr] is in tail position with respect to the
|
||||
@scheme[when] form.
|
||||
|
||||
@examples[
|
||||
(when (positive? -5)
|
||||
(display "hi"))
|
||||
(when (positive? 5)
|
||||
(display "hi")
|
||||
(display " there"))
|
||||
]}
|
||||
|
||||
@defform[(unless test-expr expr ...)]{
|
||||
|
||||
Equivalent to @scheme[(when (not test-expr) expr ...)].
|
||||
|
||||
@examples[
|
||||
(unless (positive? 5)
|
||||
(display "hi"))
|
||||
(unless (positive? -5)
|
||||
(display "hi")
|
||||
(display " there"))
|
||||
]}
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@include-section["for.scrbl"]
|
||||
|
|
|
@ -69,7 +69,7 @@ application of @scheme[-] cannot be reduced until the sub-expression
|
|||
@scheme[(+ 1 1)] is reduced.
|
||||
|
||||
Thus, the specification of each syntactic form specifies how (some of)
|
||||
it's sub-expressions are evaluated, and then how the results are
|
||||
its sub-expressions are evaluated, and then how the results are
|
||||
combined to reduce the form away.
|
||||
|
||||
The @defterm{dynamic extent} of an expression is the sequence of
|
||||
|
@ -177,7 +177,7 @@ right-hand expression must be reduced to a value.
|
|||
[{}
|
||||
(begin (code:hilite (define x 10)) (+ x 1))]
|
||||
[{(define x 10)}
|
||||
(code:hilite (begin #,void-const (+ x 1)))]
|
||||
(code:hilite (begin (void) (+ x 1)))]
|
||||
[{(define x 10)}
|
||||
(+ (code:hilite x) 1)]
|
||||
[{(define x 10)}
|
||||
|
@ -197,7 +197,7 @@ existing top-level binding:
|
|||
[{(define x 10)}
|
||||
(begin (code:hilite (set! x 8)) x)]
|
||||
[{(define x 8)}
|
||||
(code:hilite (begin #,void-const x))]
|
||||
(code:hilite (begin (void) x))]
|
||||
[{(define x 8)}
|
||||
(code:hilite x)]
|
||||
[{(define x 8)}
|
||||
|
@ -217,7 +217,7 @@ values, which are the results of expressions, and @defterm{objects},
|
|||
which hold the data referenced by a value.
|
||||
|
||||
A few kinds of objects can serve directly as values, including
|
||||
booleans, @|void-const|, and small exact integers. More generally,
|
||||
booleans, @scheme[(void)], and small exact integers. More generally,
|
||||
however, a value is a reference to an object. For example, a value can
|
||||
be a reference to a particular vector that currently holds the value
|
||||
@scheme[10] in its first slot. If an object is modified, then the
|
||||
|
@ -235,58 +235,58 @@ create objects, such as @scheme[vector], add to the set of objects:
|
|||
(define y x)
|
||||
(vector-set! x 0 11)
|
||||
(vector-ref y 0))]
|
||||
[{(define <o1> #(10 20))}
|
||||
[{(define <o1> (vector 10 20))}
|
||||
{}
|
||||
(begin (code:hilite (define x <o1>))
|
||||
(define y x)
|
||||
(vector-set! x 0 11)
|
||||
(vector-ref y 0))]
|
||||
[{(define <o1> #(10 20))}
|
||||
[{(define <o1> (vector 10 20))}
|
||||
{(define x <o1>)}
|
||||
(code:hilite (begin #,void-const
|
||||
(code:hilite (begin (void)
|
||||
(define y x)
|
||||
(vector-set! x 0 11)
|
||||
(vector-ref y 0)))]
|
||||
[{(define <o1> #(10 20))}
|
||||
[{(define <o1> (vector 10 20))}
|
||||
{(define x <o1>)}
|
||||
(begin (define y (code:hilite x))
|
||||
(vector-set! x 0 11)
|
||||
(vector-ref y 0))]
|
||||
[{(define <o1> #(10 20))}
|
||||
[{(define <o1> (vector 10 20))}
|
||||
{(define x <o1>)}
|
||||
(begin (code:hilite (define y <o1>))
|
||||
(vector-set! x 0 11)
|
||||
(vector-ref y 0))]
|
||||
[{(define <o1> #(10 20))}
|
||||
[{(define <o1> (vector 10 20))}
|
||||
{(define x <o1>)
|
||||
(define y <o1>)}
|
||||
(code:hilite (begin #,void-const
|
||||
(code:hilite (begin (void)
|
||||
(vector-set! x 0 11)
|
||||
(vector-ref y 0)))]
|
||||
[{(define <o1> #(10 20))}
|
||||
[{(define <o1> (vector 10 20))}
|
||||
{(define x <o1>)
|
||||
(define y <o1>)}
|
||||
(begin (vector-set! (code:hilite x) 0 11)
|
||||
(vector-ref y 0))]
|
||||
[{(define <o1> #(10 20))}
|
||||
[{(define <o1> (vector 10 20))}
|
||||
{(define x <o1>)
|
||||
(define y <o1>)}
|
||||
(begin (code:hilite (vector-set! <o1> 0 11))
|
||||
(vector-ref y 0))]
|
||||
[{(define <o1> #(11 20))}
|
||||
[{(define <o1> (vector 11 20))}
|
||||
{(define x <o1>)
|
||||
(define y <o1>)}
|
||||
(code:hilite (begin #,void-const
|
||||
(code:hilite (begin (void)
|
||||
(vector-ref y 0)))]
|
||||
[{(define <o1> #(11 20))}
|
||||
[{(define <o1> (vector 11 20))}
|
||||
{(define x <o1>)
|
||||
(define y <o1>)}
|
||||
(vector-ref (code:hilite y) 0)]
|
||||
[{(define <o1> #(11 20))}
|
||||
[{(define <o1> (vector 11 20))}
|
||||
{(define x <o1>)
|
||||
(define y <o1>)}
|
||||
(code:hilite (vector-ref <o1> 0))]
|
||||
[{(define <o1> #(11 20))}
|
||||
[{(define <o1> (vector 11 20))}
|
||||
{(define x <o1>)
|
||||
(define y <o1>)}
|
||||
11]
|
||||
|
@ -334,8 +334,8 @@ specified with the datatype and its associated procedures.
|
|||
In the program state
|
||||
|
||||
@prog-steps[
|
||||
[{(define <o1> #(10 20))
|
||||
(define <o2> #(0))}
|
||||
[{(define <o1> (vector 10 20))
|
||||
(define <o2> (vector 0))}
|
||||
{(define x <o1>)}
|
||||
(+ 1 x)]
|
||||
]
|
||||
|
@ -432,7 +432,7 @@ the variable is always replaced with a location by the time the
|
|||
[{(define <p1> (lambda (x) (begin (set! x 3) x)))}
|
||||
{(define f <p1>)
|
||||
(define xloc 3)}
|
||||
(code:hilite (begin #,void-const xloc))]
|
||||
(code:hilite (begin (void) xloc))]
|
||||
[{(define <p1> (lambda (x) (begin (set! x 3) x)))}
|
||||
{(define f <p1>)
|
||||
(define xloc 3)}
|
||||
|
@ -463,7 +463,7 @@ in an initial program refer to variables. A top-level binding is both
|
|||
a variable and a location. Any other variable is always replaced by a
|
||||
location at run-time, so that evaluation of expressions involves only
|
||||
locations. A single non-top-level variable, such as a procedure
|
||||
argument, can correspond to multiple locations at different times.
|
||||
argument, can correspond to different locations at different times.
|
||||
|
||||
The replacement of a variable with a location during evaluation
|
||||
implements Scheme's @defterm{lexical scoping}. For example, when the
|
||||
|
@ -473,12 +473,14 @@ procedure, including with any nested @scheme[lambda] forms. As a
|
|||
result, future references of the variable always access the same
|
||||
location.
|
||||
|
||||
@guideintro["guide:binding"]{binding}
|
||||
|
||||
An @defterm{identifier} is source-program entity. Parsing a Scheme
|
||||
program reveals that some identifiers correspond to variables, some
|
||||
refer to syntactic forms, and some are quoted to produce a symbol or a
|
||||
syntax object. An identifier @scheme[binds] another when the former is
|
||||
syntax object. An identifier @defterm{binds} another when the former is
|
||||
parsed as a variable and the latter is parsed as a reference to the
|
||||
former. An identifier is @scheme[bound] in a sub-expression if it
|
||||
former. An identifier is @defterm{bound} in a sub-expression if it
|
||||
binds any uses of the identifier in the sub-expression that are not
|
||||
otherwise bound within the sub-expression; conversely, a binding for a
|
||||
sub-expression @defterm{shadows} any bindings in its context, so that
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#reader(lib "docreader.ss" "scribble")
|
||||
@require["mz.ss"]
|
||||
|
||||
@define[cvt (schemefont "CVT")]
|
||||
|
||||
@title[#:tag "mz:syntax" #:style 'toc]{Core Syntactic Forms}
|
||||
|
||||
This section describes core syntax forms that apear in a fully
|
||||
|
@ -89,7 +91,7 @@ references are disallowed anywhere within a @scheme[module] form.
|
|||
|
||||
@defform/none[(proc-expr arg ...)]{
|
||||
|
||||
Applies a procedure, normally, when @scheme[proc-expr] is not an
|
||||
Applies a procedure, when @scheme[proc-expr] is not an
|
||||
identifier that has a transformer binding (see
|
||||
@secref["mz:expansion"]).
|
||||
|
||||
|
@ -126,8 +128,8 @@ in the application, then the procedure is called with the values of
|
|||
the @scheme[arg-expr]s. Otherwise, the @exnraise[exn:fail:contract].
|
||||
|
||||
The continuation of the procedure call is the same as the continuation
|
||||
of the application expression, so the result(s) of the application
|
||||
expression is(are) the result(s) of the procedure.
|
||||
of the application expression, so the results of the procedure are the
|
||||
results of the application expression.
|
||||
|
||||
The relative order of @scheme[_keyword]-based arguments matters only
|
||||
for the order of @scheme[_arg-expr] evaluations; the arguments are
|
||||
|
@ -162,7 +164,7 @@ according to their order in the application form.
|
|||
|
||||
Produces a procedure. The @scheme[gen-formals] determines the number of
|
||||
arguments that the procedure accepts. It is either a simple
|
||||
@scheme[formals], or one of the extended forms.
|
||||
@scheme[formals] or one of the extended forms.
|
||||
|
||||
A simple @scheme[_formals] has one of the following three forms:
|
||||
|
||||
|
@ -239,12 +241,9 @@ When multiple identifiers appear in a @scheme[gen-formals], they must be
|
|||
distinct according to @scheme[bound-identifier=?].
|
||||
|
||||
If the procedure procedure by @scheme[lambda] is applied to fewer or
|
||||
more arguments than it accepts, the @exnraise[exn:fail:contract]. If
|
||||
@scheme[gen-formals] includes @scheme[keyword]s and an application
|
||||
includes too few arguments before the keyword section, the same
|
||||
keyword in multiple positions, or a keyword that is not among the
|
||||
@scheme[gen-formals] @scheme[_keyword]s, then the
|
||||
@exnraise[exn:fail:contract].
|
||||
more by-position or arguments than it accepts, to by-keyword arguments
|
||||
that it does not accept, or without required by-keyword arguments, then
|
||||
the @exnraise[exn:fail:contract].
|
||||
|
||||
The last @scheme[body] expression is in tail position with respect to
|
||||
the procedure body.
|
||||
|
@ -322,9 +321,9 @@ within the @scheme[body]s to the procedure itself.}
|
|||
|
||||
Similar to @scheme[let], but evaluates the @scheme[val-expr]s one by
|
||||
one, creating a location for each @scheme[id] as soon as the value is
|
||||
availablek. The @scheme[id]s are bound in the remaining @scheme[val-expr]s
|
||||
available. The @scheme[id]s are bound in the remaining @scheme[val-expr]s
|
||||
as well as the @scheme[body]s, and the @scheme[id]s need not be
|
||||
distinct.
|
||||
distinct; later bindings shadow earlier bindings.
|
||||
|
||||
@examples[
|
||||
(let ([x 1]
|
||||
|
@ -352,8 +351,9 @@ created first and filled with @|undefined-const|, and all
|
|||
|
||||
@defform[(let-values ([(id ...) val-expr] ...) body ...+)]{ Like
|
||||
@scheme[let], except that each @scheme[val-expr] must produce as many
|
||||
values as corresponding @scheme[id]s. A separate location is created
|
||||
for each @scheme[id], all of which are bound in the @scheme[body]s.
|
||||
values as corresponding @scheme[id]s, otherwise the
|
||||
@exnraise[exn:fail:contract]. A separate location is created for each
|
||||
@scheme[id], all of which are bound in the @scheme[body]s.
|
||||
|
||||
@examples[
|
||||
(let-values ([(x y) (quotient/remainder 10 3)])
|
||||
|
@ -392,8 +392,131 @@ and in the @scheme[body]s.
|
|||
]}
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Sequencing: @scheme[begin]}
|
||||
@section[#:tag "mz:if"]{Conditionals: @scheme[if]}
|
||||
|
||||
@defform[(if test-expr then-expr else-expr)]{
|
||||
|
||||
Evaluates @scheme[test-expr]. If it produces any value other than
|
||||
@scheme[#f], then @scheme[then-expr] is evaluated, and its results are
|
||||
the result for the @scheme[if] form. Otherwise, @scheme[else-expr] is
|
||||
evaluated, and its results are the result for the @scheme[if]
|
||||
form. The @scheme[then-expr] and @scheme[else-expr] are in tail
|
||||
position with respect to the @scheme[if] form.
|
||||
|
||||
@examples[
|
||||
(if (positive? -5) (error "doesn't get here") 2)
|
||||
(if (positive? 5) 1 (error "doesn't get here"))
|
||||
]}
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "mz:define"]{Definitions: @scheme[define] and @scheme[define-values]}
|
||||
|
||||
@defform*/subs[[(define id expr)
|
||||
(define (head args) body ...+)]
|
||||
([head id
|
||||
(head args)]
|
||||
[args (code:line arg ...)
|
||||
(code:line arg ... #, @schemeparenfont{.} rest-id)]
|
||||
[arg arg-id
|
||||
[arg-id default-expr]
|
||||
(code:line keyword arg-id)
|
||||
(code:line keyword [arg-id default-expr])])]{
|
||||
|
||||
The first form binds @scheme[id] to the result of @scheme[expr], and
|
||||
the second form binds @scheme[id] to a procedure. In the second case,
|
||||
the generation procedure is @scheme[(#,cvt (head args) body ...+)],
|
||||
using the @|cvt| meta-function defined as follows:
|
||||
|
||||
@schemeblock[
|
||||
(#,cvt (id . _gen-formals) . _datum) = (lambda _gen-formals . _datum)
|
||||
(#,cvt (head . _gen-formals) . _datum) = (lambda _gen-formals expr)
|
||||
#, @elem{if} (#,cvt head . _datum) = expr
|
||||
]
|
||||
|
||||
At the top level, the top-level binding @scheme[id] is created after
|
||||
evaluating @scheme[expr], if it does not exist already, and the
|
||||
top-level mapping of @scheme[id] (see @secref["mz:namespace"]) is set
|
||||
to the binding at the same time.
|
||||
|
||||
@defexamples[
|
||||
(define x 10)
|
||||
x
|
||||
]
|
||||
@def+int[
|
||||
(define (f x)
|
||||
(+ x 1))
|
||||
(f 10)
|
||||
]
|
||||
|
||||
@def+int[
|
||||
(define ((f x) [y 20])
|
||||
(+ x y))
|
||||
((f 10) 30)
|
||||
((f 10))
|
||||
]
|
||||
}
|
||||
|
||||
@defform[(define-values (id ...) expr)]{
|
||||
|
||||
Evaluates the @scheme[expr], and binds the results to the
|
||||
@scheme[id]s, in order, if the number of results matches the number of
|
||||
@scheme[id]s; if @scheme[expr] produces a different number of results,
|
||||
the @exnraise[exn:fail:contract].
|
||||
|
||||
At the top level, the top-level binding for each @scheme[id] is
|
||||
created after evaluating @scheme[expr], if it does not exist already,
|
||||
and the top-level mapping of each @scheme[id] (see
|
||||
@secref["mz:namespace"]) is set to the binding at the same time.
|
||||
|
||||
@defexamples[
|
||||
(define-values () (values))
|
||||
(define-values (x y z) (values 1 2 3))
|
||||
z
|
||||
]
|
||||
}
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Sequencing: @scheme[begin] and @scheme[begin0]}
|
||||
|
||||
@defform*[[(begin form ...)
|
||||
(begin expr ...+)]]{
|
||||
|
||||
The first form applies when @scheme[begin] appears at the top level,
|
||||
at module level, or in an internal-definition position (before any
|
||||
expression in the internal-definition sequence). In that case, the
|
||||
@scheme[begin] form is equivalent to splicing the @scheme[form]s into
|
||||
the enclosing context.
|
||||
|
||||
The second form applies for @scheme[begin] in an expression position.
|
||||
In that case, the @scheme[expr]s are evaluated in order, and the
|
||||
results are ignored for all but the last @scheme[expr]. The last
|
||||
@scheme[expr] is in tail position with respect to the @scheme[begin]
|
||||
form.
|
||||
|
||||
@examples[
|
||||
(begin
|
||||
(define x 10)
|
||||
x)
|
||||
(+ 1 (begin
|
||||
(printf "hi\n")
|
||||
2))
|
||||
(let-values ([(x y) (begin
|
||||
(values 1 2 3)
|
||||
(values 1 2))])
|
||||
(list x y))
|
||||
]}
|
||||
|
||||
@defform[(begin0 expr body ...+)]{
|
||||
|
||||
Evaluates the @scheme[expr], then evaluates the @scheme[body]s,
|
||||
ignoring the @scheme[body] results. The results of the @scheme[expr]
|
||||
are the results of the @scheme[begin0] form, but the @scheme[expr] is
|
||||
in tail position only if no @scheme[body]s are present.
|
||||
|
||||
|
||||
|
||||
@examples[
|
||||
(begin0
|
||||
(values 1 2)
|
||||
(printf "hi\n"))
|
||||
]}
|
Loading…
Reference in New Issue
Block a user