partly rackety guide
This commit is contained in:
parent
4537240f1f
commit
1fedf04739
|
@ -611,43 +611,64 @@
|
|||
((loop init-line! (if qq? quote-depth +inf.0) qq?) (unbox (syntax-e c))))]
|
||||
[(hash? (syntax-e c))
|
||||
(advance c init-line!)
|
||||
(let ([equal-table? (not (hash-eq? (syntax-e c)))]
|
||||
(let ([equal-table? (hash-equal? (syntax-e c))]
|
||||
[eqv-table? (hash-eq? (syntax-e c))]
|
||||
[quote-depth (to-quoted "`" qq? quote-depth out color? inc-src-col)])
|
||||
(out (if equal-table?
|
||||
"#hash"
|
||||
"#hasheq")
|
||||
(if eqv-table?
|
||||
"#hasheqv"
|
||||
"#hasheq"))
|
||||
value-color)
|
||||
(let ([delta (+ 5 (if equal-table? 2 0))]
|
||||
(let ([delta (+ 5 (if equal-table? 0 (if eqv-table? 3 2)))]
|
||||
[orig-col src-col])
|
||||
(set! src-col (+ src-col delta))
|
||||
(hash-set! next-col-map src-col dest-col)
|
||||
((loop init-line! (if qq? quote-depth +inf.0) qq?)
|
||||
(let* ([l (sort (hash-map (syntax-e c) cons)
|
||||
(lambda (a b)
|
||||
(< (or (syntax-position (cdr a)) -inf.0)
|
||||
(or (syntax-position (cdr b)) -inf.0))))]
|
||||
[l2 (for/list ([p (in-list l)])
|
||||
(let* ([tentative (syntax-ize (car p) 0)]
|
||||
[width (syntax-span tentative)])
|
||||
(datum->syntax
|
||||
#f
|
||||
(make-forced-pair
|
||||
(syntax-ize (car p)
|
||||
(max 0 (- (syntax-column (cdr p))
|
||||
width
|
||||
3))
|
||||
(syntax-line (cdr p)))
|
||||
(cdr p))
|
||||
(vector 'here
|
||||
(syntax-line (cdr p))
|
||||
(max 0 (- (syntax-column (cdr p)) width 4))
|
||||
(max 1 (- (syntax-position (cdr p)) width 4))
|
||||
(+ (syntax-span (cdr p)) width 5)))))])
|
||||
(datum->syntax #f l2 (vector (syntax-source c)
|
||||
(syntax-line c)
|
||||
(+ (syntax-column c) delta)
|
||||
(+ (syntax-position c) delta)
|
||||
(max 1 (- (syntax-span c) delta))))))
|
||||
(let*-values ([(l) (sort (hash-map (syntax-e c) cons)
|
||||
(lambda (a b)
|
||||
(< (or (syntax-position (cdr a)) -inf.0)
|
||||
(or (syntax-position (cdr b)) -inf.0))))]
|
||||
[(col0) (+ (syntax-column c) delta 2)]
|
||||
[(l2 pos line) (for/fold ([l2 null][col col0][line (syntax-line c)])
|
||||
([p (in-list l)])
|
||||
(let* ([tentative (syntax-ize (car p) 0)]
|
||||
[width (syntax-span tentative)]
|
||||
[col (if (= line (syntax-line (cdr p)))
|
||||
col
|
||||
col0)])
|
||||
(let ([key
|
||||
(let ([e (syntax-ize (car p)
|
||||
(max 0 (- (syntax-column (cdr p))
|
||||
width
|
||||
3))
|
||||
(syntax-line (cdr p)))])
|
||||
(if ((syntax-column e) . <= . col)
|
||||
e
|
||||
(datum->syntax #f
|
||||
(syntax-e e)
|
||||
(vector (syntax-source e)
|
||||
(syntax-line e)
|
||||
col
|
||||
(syntax-position e)
|
||||
(+ (syntax-span e) (- (syntax-column e) col))))))])
|
||||
(let ([elem
|
||||
(datum->syntax
|
||||
#f
|
||||
(make-forced-pair key (cdr p))
|
||||
(vector 'here
|
||||
(syntax-line (cdr p))
|
||||
(max 0 (- (syntax-column key) 1))
|
||||
(max 1 (- (syntax-position key) 1))
|
||||
(+ (syntax-span (cdr p)) (syntax-span key) 5)))])
|
||||
(values (cons elem l2)
|
||||
(+ (syntax-column elem) (syntax-span elem) 2)
|
||||
(syntax-line elem))))))])
|
||||
(datum->syntax #f (reverse l2) (vector (syntax-source c)
|
||||
(syntax-line c)
|
||||
(+ (syntax-column c) delta)
|
||||
(+ (syntax-position c) delta)
|
||||
(max 1 (- (syntax-span c) delta))))))
|
||||
(set! src-col (+ orig-col (syntax-span c)))))]
|
||||
[(graph-reference? (syntax-e c))
|
||||
(advance c init-line!)
|
||||
|
|
|
@ -12,16 +12,16 @@ An expression of the form
|
|||
]
|
||||
|
||||
is a function call---also known as a @defterm{procedure
|
||||
application}---when @scheme[_proc-expr] is not an identifier that is
|
||||
bound as a syntax transformer (such as @scheme[if] or
|
||||
@scheme[define]).
|
||||
application}---when @racket[_proc-expr] is not an identifier that is
|
||||
bound as a syntax transformer (such as @racket[if] or
|
||||
@racket[define]).
|
||||
|
||||
@section{Evaluation Order and Arity}
|
||||
|
||||
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] produces a function that accepts
|
||||
as many arguments as supplied @scheme[_arg-expr]s, the function is
|
||||
@racket[_proc-expr] and all @racket[_arg-expr]s in order (left to
|
||||
right). Then, if @racket[_proc-expr] produces a function that accepts
|
||||
as many arguments as supplied @racket[_arg-expr]s, the function is
|
||||
called. Otherwise, an exception is raised.
|
||||
|
||||
@examples[
|
||||
|
@ -31,10 +31,10 @@ called. Otherwise, an exception is raised.
|
|||
(1 2 3)
|
||||
]
|
||||
|
||||
Some functions, such as @scheme[cons], accept a fixed number of
|
||||
arguments. Some functions, such as @scheme[+] or @scheme[list], accept
|
||||
Some functions, such as @racket[cons], accept a fixed number of
|
||||
arguments. Some functions, such as @racket[+] or @racket[list], accept
|
||||
any number of arguments. Some functions accept a range of argument
|
||||
counts; for example @scheme[substring] accepts either two or three
|
||||
counts; for example @racket[substring] accepts either two or three
|
||||
arguments. A function's @idefterm{arity} is the number of arguments
|
||||
that it accepts.
|
||||
|
||||
|
@ -42,9 +42,9 @@ that it accepts.
|
|||
@section[#:tag "keyword-args"]{Keyword Arguments}
|
||||
|
||||
Some functions accept @defterm{keyword arguments} in addition to
|
||||
by-position arguments. For that case, an @scheme[_arg] can be an
|
||||
@scheme[_arg-keyword _arg-expr] sequence instead of just a
|
||||
@scheme[_arg-expr]:
|
||||
by-position arguments. For that case, an @racket[_arg] can be an
|
||||
@racket[_arg-keyword _arg-expr] sequence instead of just a
|
||||
@racket[_arg-expr]:
|
||||
|
||||
@guideother{@secref["keywords"] introduces keywords.}
|
||||
|
||||
|
@ -56,37 +56,37 @@ by-position arguments. For that case, an @scheme[_arg] can be an
|
|||
|
||||
For example,
|
||||
|
||||
@schemeblock[(go "super.ss" #:mode 'fast)]
|
||||
@racketblock[(go "super.ss" #:mode 'fast)]
|
||||
|
||||
calls the function bound to @scheme[go] with @scheme["super.ss"] as a
|
||||
by-position argument, and with @scheme['fast] as an argument
|
||||
associated with the @scheme[#:mode] keyword. A keyword is implicitly
|
||||
calls the function bound to @racket[go] with @racket["super.ss"] as a
|
||||
by-position argument, and with @racket['fast] as an argument
|
||||
associated with the @racket[#:mode] keyword. A keyword is implicitly
|
||||
paired with the expression that follows it.
|
||||
|
||||
Since a keyword by itself is not an expression, then
|
||||
|
||||
@schemeblock[(go "super.ss" #:mode #:fast)]
|
||||
@racketblock[(go "super.ss" #:mode #:fast)]
|
||||
|
||||
is a syntax error. The @scheme[#:mode] keyword must be followed by an
|
||||
expression to produce an argument value, and @scheme[#:fast] is not an
|
||||
is a syntax error. The @racket[#:mode] keyword must be followed by an
|
||||
expression to produce an argument value, and @racket[#:fast] is not an
|
||||
expression.
|
||||
|
||||
The order of keyword @scheme[_arg]s determines the order in which
|
||||
@scheme[_arg-expr]s are evaluated, but a function accepts keyword
|
||||
The order of keyword @racket[_arg]s determines the order in which
|
||||
@racket[_arg-expr]s are evaluated, but a function accepts keyword
|
||||
arguments independent of their position in the argument list. The
|
||||
above call to @scheme[go] can be equivalently written
|
||||
above call to @racket[go] can be equivalently written
|
||||
|
||||
@schemeblock[(go #:mode 'fast "super.ss")]
|
||||
@racketblock[(go #:mode 'fast "super.ss")]
|
||||
|
||||
@refdetails["application"]{procedure applications}
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "apply"]{The @scheme[apply] Function}
|
||||
@section[#:tag "apply"]{The @racket[apply] Function}
|
||||
|
||||
The syntax for function calls supports any number of arguments, but a
|
||||
specific call always specifies a fixed number of arguments. As a
|
||||
result, a function that takes a list of arguments cannot directly
|
||||
apply a function like @scheme[+] to all of the items in the list:
|
||||
apply a function like @racket[+] to all of the items in the list:
|
||||
|
||||
@def+int[
|
||||
(define (avg lst) (code:comment @#,elem{doesn't work...})
|
||||
|
@ -102,7 +102,7 @@ apply a function like @scheme[+] to all of the items in the list:
|
|||
(avg '(1 2))
|
||||
]
|
||||
|
||||
The @scheme[apply] function offers a way around this restriction. It
|
||||
The @racket[apply] function offers a way around this restriction. It
|
||||
takes a function and a @italic{list} arguments, and it applies the
|
||||
function to the arguments:
|
||||
|
||||
|
@ -114,9 +114,9 @@ function to the arguments:
|
|||
(avg '(1 2 3 4))
|
||||
]
|
||||
|
||||
As a convenience, the @scheme[apply] function accepts additional
|
||||
As a convenience, the @racket[apply] function accepts additional
|
||||
arguments between the function and the list. The additional arguments
|
||||
are effectively @scheme[cons]ed onto the argument list:
|
||||
are effectively @racket[cons]ed onto the argument list:
|
||||
|
||||
@def+int[
|
||||
(define (anti-sum lst)
|
||||
|
@ -124,15 +124,15 @@ are effectively @scheme[cons]ed onto the argument list:
|
|||
(anti-sum '(1 2 3))
|
||||
]
|
||||
|
||||
The @scheme[apply] function supports only by-position arguments. To
|
||||
The @racket[apply] function supports only by-position arguments. To
|
||||
apply a function with keyword arguments, use the
|
||||
@scheme[keyword-apply] function, which accepts a function to apply
|
||||
@racket[keyword-apply] function, which accepts a function to apply
|
||||
and three lists. The first two lists are in parallel, where the first
|
||||
list contains keywords (sorted by @scheme[keyword<]), and the second
|
||||
list contains keywords (sorted by @racket[keyword<]), and the second
|
||||
list contains a corresponding argument for each keyword. The third
|
||||
list contains by-position function arguments, as for @scheme[apply].
|
||||
list contains by-position function arguments, as for @racket[apply].
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(keyword-apply go
|
||||
'(#:mode)
|
||||
'(fast)
|
||||
|
|
|
@ -5,25 +5,25 @@
|
|||
|
||||
@title[#:tag "begin"]{Sequencing}
|
||||
|
||||
Scheme programmers prefer to write programs with as few side-effects
|
||||
Racket programmers prefer to write programs with as few side-effects
|
||||
as possible, since purely functional code is more easily tested and
|
||||
composed into larger programs. Interaction with the external
|
||||
environment, however, requires sequencing, such as when writing to a
|
||||
display, opening a graphical window, or manipulating a file on disk.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Effects Before: @scheme[begin]}
|
||||
@section{Effects Before: @racket[begin]}
|
||||
|
||||
@refalso["begin"]{@scheme[begin]}
|
||||
@refalso["begin"]{@racket[begin]}
|
||||
|
||||
A @scheme[begin] expression sequences expressions:
|
||||
A @racket[begin] expression sequences expressions:
|
||||
|
||||
@specform[(begin expr ...+)]{}
|
||||
|
||||
The @scheme[_expr]s are evaluated in order, and the result of all but
|
||||
the last @scheme[_expr] is ignored. The result from the last
|
||||
@scheme[_expr] is the result of the @scheme[begin] form, and it is in
|
||||
tail position with respect to the @scheme[begin] form.
|
||||
The @racket[_expr]s are evaluated in order, and the result of all but
|
||||
the last @racket[_expr] is ignored. The result from the last
|
||||
@racket[_expr] is the result of the @racket[begin] form, and it is in
|
||||
tail position with respect to the @racket[begin] form.
|
||||
|
||||
@defexamples[
|
||||
(define (print-triangle height)
|
||||
|
@ -36,8 +36,8 @@ tail position with respect to the @scheme[begin] form.
|
|||
(print-triangle 4)
|
||||
]
|
||||
|
||||
Many forms, such as @scheme[lambda] or @scheme[cond] support a
|
||||
sequence of expressions even without a @scheme[begin]. Such positions are
|
||||
Many forms, such as @racket[lambda] or @racket[cond] support a
|
||||
sequence of expressions even without a @racket[begin]. Such positions are
|
||||
sometimes said to have an @defterm{implicit begin}.
|
||||
|
||||
@defexamples[
|
||||
|
@ -50,10 +50,10 @@ sometimes said to have an @defterm{implicit begin}.
|
|||
(print-triangle 4)
|
||||
]
|
||||
|
||||
The @scheme[begin] form is special at the top level, at module level,
|
||||
or as a @scheme[body] after only internal definitions. In those
|
||||
The @racket[begin] form is special at the top level, at module level,
|
||||
or as a @racket[body] after only internal definitions. In those
|
||||
positions, instead of forming an expression, the content of
|
||||
@scheme[begin] is spliced into the surrounding context.
|
||||
@racket[begin] is spliced into the surrounding context.
|
||||
|
||||
@defexamples[
|
||||
(let ([curly 0])
|
||||
|
@ -67,18 +67,18 @@ This splicing behavior is mainly useful for macros, as we discuss
|
|||
later in @secref["macros"].
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Effects After: @scheme[begin0]}
|
||||
@section{Effects After: @racket[begin0]}
|
||||
|
||||
@refalso["begin"]{@scheme[begin0]}
|
||||
@refalso["begin"]{@racket[begin0]}
|
||||
|
||||
A @scheme[begin0] expression has the same syntax as a @scheme[begin]
|
||||
A @racket[begin0] expression has the same syntax as a @racket[begin]
|
||||
expression:
|
||||
|
||||
@specform[(begin0 expr ...+)]{}
|
||||
|
||||
The difference is that @scheme[begin0] returns the result of the first
|
||||
@scheme[expr], instead of the result of the last @scheme[expr]. The
|
||||
@scheme[begin0] form is useful for implementing side-effects that
|
||||
The difference is that @racket[begin0] returns the result of the first
|
||||
@racket[expr], instead of the result of the last @racket[expr]. The
|
||||
@racket[begin0] form is useful for implementing side-effects that
|
||||
happen after a computation, especially in the case where the
|
||||
computation produces an unknown number of results.
|
||||
|
||||
|
@ -93,26 +93,26 @@ computation produces an unknown number of results.
|
|||
]
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "when+unless"]{Effects If...: @scheme[when] and @scheme[unless]}
|
||||
@section[#:tag "when+unless"]{Effects If...: @racket[when] and @racket[unless]}
|
||||
|
||||
@refalso["when+unless"]{@scheme[when] and @scheme[unless]}
|
||||
@refalso["when+unless"]{@racket[when] and @racket[unless]}
|
||||
|
||||
The @scheme[when] form combines an @scheme[if]-style conditional with
|
||||
The @racket[when] form combines an @racket[if]-style conditional with
|
||||
sequencing for the ``then'' clause and no ``else'' clause:
|
||||
|
||||
@specform[(when test-expr then-expr ...)]
|
||||
|
||||
If @scheme[_test-expr] produces a true value, then all of the
|
||||
@scheme[_then-expr]s are evaluated. Otherwise, no @scheme[_then-expr]s
|
||||
If @racket[_test-expr] produces a true value, then all of the
|
||||
@racket[_then-expr]s are evaluated. Otherwise, no @racket[_then-expr]s
|
||||
are evaluated. The result is @|void-const| in any case.
|
||||
|
||||
The @scheme[unless] form is similar:
|
||||
The @racket[unless] form is similar:
|
||||
|
||||
@specform[(unless test-expr then-expr ...)]
|
||||
|
||||
The difference is that the @scheme[_test-expr] result is inverted: the
|
||||
@scheme[_then-expr]s are evaluated only if the @scheme[_test-expr]
|
||||
result is @scheme[#f].
|
||||
The difference is that the @racket[_test-expr] result is inverted: the
|
||||
@racket[_then-expr]s are evaluated only if the @racket[_test-expr]
|
||||
result is @racket[#f].
|
||||
|
||||
@defexamples[
|
||||
(define (enumerate lst)
|
||||
|
|
|
@ -7,19 +7,19 @@
|
|||
|
||||
The context of an expression determines the meaning of identifiers
|
||||
that appear in the expression. In particular, starting a module with
|
||||
the language @schememodname[scheme], as in
|
||||
the language @racketmodname[racket], as in
|
||||
|
||||
@schememod[scheme]
|
||||
@racketmod[racket]
|
||||
|
||||
means that, within the module, the identifiers described in this guide
|
||||
start with the meaning described here: @scheme[cons] refers to the
|
||||
function that creates a pair, @scheme[car] refers to the function
|
||||
start with the meaning described here: @racket[cons] refers to the
|
||||
function that creates a pair, @racket[car] refers to the function
|
||||
that extracts the first element of a pair, and so on.
|
||||
|
||||
@guideother{@secref["symbols"] introduces the syntax of
|
||||
identifiers.}
|
||||
|
||||
Forms like @scheme[define], @scheme[lambda], and @scheme[let]
|
||||
Forms like @racket[define], @racket[lambda], and @racket[let]
|
||||
associate a meaning with one or more identifiers; that is, they
|
||||
@defterm{bind} identifiers. The part of the program for which the
|
||||
binding applies is the @defterm{scope} of the binding. The set of
|
||||
|
@ -28,8 +28,8 @@ bindings in effect for a given expression is the expression's
|
|||
|
||||
For example, in
|
||||
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
|
||||
(define f
|
||||
(lambda (x)
|
||||
|
@ -39,19 +39,19 @@ scheme
|
|||
(f 10)
|
||||
]
|
||||
|
||||
the @scheme[define] is a binding of @scheme[f], the @scheme[lambda]
|
||||
has a binding for @scheme[x], and the @scheme[let] has a binding for
|
||||
@scheme[y]. The scope of the binding for @scheme[f] is the entire
|
||||
module; the scope of the @scheme[x] binding is @scheme[(let ([y 5]) (+
|
||||
x y))]; and the scope of the @scheme[y] binding is just @scheme[(+ x
|
||||
y)]. The environment of @scheme[(+ x y)] includes bindings for
|
||||
@scheme[y], @scheme[x], and @scheme[f], as well as everything in
|
||||
@schememodname[scheme].
|
||||
the @racket[define] is a binding of @racket[f], the @racket[lambda]
|
||||
has a binding for @racket[x], and the @racket[let] has a binding for
|
||||
@racket[y]. The scope of the binding for @racket[f] is the entire
|
||||
module; the scope of the @racket[x] binding is @racket[(let ([y 5]) (+
|
||||
x y))]; and the scope of the @racket[y] binding is just @racket[(+ x
|
||||
y)]. The environment of @racket[(+ x y)] includes bindings for
|
||||
@racket[y], @racket[x], and @racket[f], as well as everything in
|
||||
@racketmodname[racket].
|
||||
|
||||
A module-level @scheme[define] can bind only identifiers that are not
|
||||
already bound within the module. For example, @scheme[(define cons 1)]
|
||||
is a syntax error in a @schememodname[scheme] module, since @scheme[cons]
|
||||
is provided by @schememodname[scheme]. A local @scheme[define] or other
|
||||
A module-level @racket[define] can bind only identifiers that are not
|
||||
already bound within the module. For example, @racket[(define cons 1)]
|
||||
is a syntax error in a @racketmodname[racket] module, since @racket[cons]
|
||||
is provided by @racketmodname[racket]. A local @racket[define] or other
|
||||
binding forms, however, can give a new local binding for an identifier
|
||||
that already has a binding; such a binding @defterm{shadows} the
|
||||
existing binding.
|
||||
|
@ -65,18 +65,18 @@ existing binding.
|
|||
(f list)
|
||||
]
|
||||
|
||||
Even identifiers like @scheme[define] and @scheme[lambda] get their
|
||||
Even identifiers like @racket[define] and @racket[lambda] get their
|
||||
meanings from bindings, though they have @defterm{transformer}
|
||||
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
|
||||
value bindings. Since @racket[define] has a transformer binding, the
|
||||
identifier @racketidfont{define} cannot be used by itself to get a
|
||||
value. However, the normal binding for @racketidfont{define} can be
|
||||
shadowed.
|
||||
|
||||
@examples[
|
||||
define
|
||||
(eval:alts (let ([@#,schemeidfont{define} 5]) @#,schemeidfont{define}) (let ([define 5]) define))
|
||||
(eval:alts (let ([@#,racketidfont{define} 5]) @#,racketidfont{define}) (let ([define 5]) define))
|
||||
]
|
||||
|
||||
Shadowing standard bindings in this way is rarely a good idea, but the
|
||||
possibility is an inherent part of Scheme's flexibility.
|
||||
possibility is an inherent part of Racket's flexibility.
|
||||
|
|
|
@ -5,15 +5,15 @@
|
|||
|
||||
@title[#:tag "booleans"]{Booleans}
|
||||
|
||||
Scheme has two distinguished constants to represent boolean values:
|
||||
@scheme[#t] for true and @scheme[#f] for false. Uppercase
|
||||
@schemevalfont{#T} and @schemevalfont{#F} are parsed as the same
|
||||
Racket has two distinguished constants to represent boolean values:
|
||||
@racket[#t] for true and @racket[#f] for false. Uppercase
|
||||
@racketvalfont{#T} and @racketvalfont{#F} are parsed as the same
|
||||
values, but the lowercase forms are preferred.
|
||||
|
||||
The @scheme[boolean?] procedure recognizes the two boolean
|
||||
constants. In the result of a test expression for @scheme[if],
|
||||
@scheme[cond], @scheme[and], @scheme[or], etc., however, any value
|
||||
other than @scheme[#f] counts as true.
|
||||
The @racket[boolean?] procedure recognizes the two boolean
|
||||
constants. In the result of a test expression for @racket[if],
|
||||
@racket[cond], @racket[and], @racket[or], etc., however, any value
|
||||
other than @racket[#f] counts as true.
|
||||
|
||||
@examples[
|
||||
(= 2 (+ 1 1))
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
@title[#:tag "bytestrings"]{Bytes and Byte Strings}
|
||||
|
||||
A @deftech{byte} is an exact integer between @scheme[0] and
|
||||
@scheme[255], inclusive. The @scheme[byte?] predicate recognizes
|
||||
A @deftech{byte} is an exact integer between @racket[0] and
|
||||
@racket[255], inclusive. The @racket[byte?] predicate recognizes
|
||||
numbers that represent bytes.
|
||||
|
||||
@examples[
|
||||
|
@ -36,23 +36,23 @@ b
|
|||
b
|
||||
]
|
||||
|
||||
The @scheme[display] form of a byte string writes its raw bytes to the
|
||||
The @racket[display] form of a byte string writes its raw bytes to the
|
||||
current output port (see @secref["i/o"]). Technically,
|
||||
@scheme[display] of a normal (i.e,. character) string prints the UTF-8
|
||||
@racket[display] of a normal (i.e,. character) string prints the UTF-8
|
||||
encoding of the string to the current output port, since output is
|
||||
ultimately defined in terms of bytes; @scheme[display] of a byte
|
||||
ultimately defined in terms of bytes; @racket[display] of a byte
|
||||
string, however, writes the raw bytes with no encoding. Along the same
|
||||
lines, when this documentation shows output, it technically shows the
|
||||
UTF-8-decoded form of the output.
|
||||
|
||||
@examples[
|
||||
(display #"Apple")
|
||||
(eval:alts (code:line (display @#,schemevalfont{"\316\273"}) (code:comment @#,t{same as @scheme["\316\273"]}))
|
||||
(eval:alts (code:line (display @#,racketvalfont{"\316\273"}) (code:comment @#,t{same as @racket["\316\273"]}))
|
||||
(display "\316\273"))
|
||||
(code:line (display #"\316\273") (code:comment @#,t{UTF-8 encoding of @elem["\u03BB"]}))
|
||||
]
|
||||
|
||||
For explicitly converting between strings and byte strings, Scheme
|
||||
For explicitly converting between strings and byte strings, Racket
|
||||
supports three kinds of encodings directly: UTF-8, Latin-1, and the
|
||||
current locale's encoding. General facilities for byte-to-byte
|
||||
conversions (especially to and from UTF-8) fill the gap to support
|
||||
|
|
|
@ -2,25 +2,25 @@
|
|||
@(require scribble/manual
|
||||
scribble/eval
|
||||
"guide-utils.ss"
|
||||
(for-label scheme/match))
|
||||
(for-label racket/match))
|
||||
|
||||
@title[#:tag "case"]{Simple Dispatch: @scheme[case]}
|
||||
@title[#:tag "case"]{Simple Dispatch: @racket[case]}
|
||||
|
||||
The @scheme[case] form dispatches to a clause by matching the result
|
||||
The @racket[case] form dispatches to a clause by matching the result
|
||||
of an expression to the values for the clause:
|
||||
|
||||
@specform[(case expr
|
||||
[(datum ...+) expr ...+]
|
||||
...)]
|
||||
|
||||
Each @scheme[_datum] will be compared to the result of the first
|
||||
@scheme[_expr] using @scheme[eqv?]. Since @scheme[eqv?] doesn't work on
|
||||
many kinds of values, notably strings and lists, each @scheme[_datum]
|
||||
Each @racket[_datum] will be compared to the result of the first
|
||||
@racket[_expr] using @racket[eqv?]. Since @racket[eqv?] doesn't work on
|
||||
many kinds of values, notably strings and lists, each @racket[_datum]
|
||||
is typically a number, symbol, or boolean.
|
||||
|
||||
Multiple @scheme[_datum]s can be supplied for each clause, and the
|
||||
corresponding @scheme[_expr] is evaluated of any of the
|
||||
@scheme[_datum]s match.
|
||||
Multiple @racket[_datum]s can be supplied for each clause, and the
|
||||
corresponding @racket[_expr] is evaluated of any of the
|
||||
@racket[_datum]s match.
|
||||
|
||||
@examples[
|
||||
(let ([v (random 6)])
|
||||
|
@ -32,8 +32,8 @@ corresponding @scheme[_expr] is evaluated of any of the
|
|||
[(3 4 5) 'many]))
|
||||
]
|
||||
|
||||
The last clause of a @scheme[case] form can use @scheme[else], just
|
||||
like @scheme[cond]:
|
||||
The last clause of a @racket[case] form can use @racket[else], just
|
||||
like @racket[cond]:
|
||||
|
||||
@examples[
|
||||
(case (random 6)
|
||||
|
@ -43,5 +43,5 @@ like @scheme[cond]:
|
|||
[else 'many])
|
||||
]
|
||||
|
||||
For more general pattern matching, use @scheme[match], which is
|
||||
For more general pattern matching, use @racket[match], which is
|
||||
introduced in @secref["match"].
|
||||
|
|
|
@ -17,25 +17,25 @@ shown with @litchar{\u} when the string is printed.
|
|||
|
||||
@refdetails/gory["parse-string"]{the syntax of strings}
|
||||
|
||||
The @scheme[display] procedure directly writes the characters of a
|
||||
The @racket[display] procedure directly writes the characters of a
|
||||
string to the current output port (see @secref["i/o"]), in contrast
|
||||
to the string-constant syntax used to print a string result.
|
||||
|
||||
@examples[
|
||||
"Apple"
|
||||
(eval:alts @#,schemevalfont{"\u03BB"} "\u03BB")
|
||||
(eval:alts @#,racketvalfont{"\u03BB"} "\u03BB")
|
||||
(display "Apple")
|
||||
(display "a \"quoted\" thing")
|
||||
(display "two\nlines")
|
||||
(eval:alts (display @#,schemevalfont{"\u03BB"}) (display "\u03BB"))
|
||||
(eval:alts (display @#,racketvalfont{"\u03BB"}) (display "\u03BB"))
|
||||
]
|
||||
|
||||
A string can be mutable or immutable; strings written directly as
|
||||
expressions are immutable, but most other strings are mutable. The
|
||||
@scheme[make-string] procedure creates a mutable string given a length
|
||||
and optional fill character. The @scheme[string-ref] procedure
|
||||
@racket[make-string] procedure creates a mutable string given a length
|
||||
and optional fill character. The @racket[string-ref] procedure
|
||||
accesses a character from a string (with 0-based indexing); the
|
||||
@scheme[string-set!] procedure changes a character in a mutable
|
||||
@racket[string-set!] procedure changes a character in a mutable
|
||||
string.
|
||||
|
||||
@examples[
|
||||
|
@ -51,9 +51,9 @@ String ordering and case operations are generally
|
|||
users. A few @defterm{locale-dependent} operations are provided that
|
||||
allow the way that strings are case-folded and sorted to depend on the
|
||||
end-user's locale. If you're sorting strings, for example, use
|
||||
@scheme[string<?] or @scheme[string-ci<?] if the sort result should be
|
||||
consistent across machines and users, but use @scheme[string-locale<?]
|
||||
or @scheme[string-locale-ci<?] if the sort is purely to order strings
|
||||
@racket[string<?] or @racket[string-ci<?] if the sort result should be
|
||||
consistent across machines and users, but use @racket[string-locale<?]
|
||||
or @racket[string-locale-ci<?] if the sort is purely to order strings
|
||||
for an end user.
|
||||
|
||||
@examples[
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
@title[#:tag "characters"]{Characters}
|
||||
|
||||
A Scheme @deftech{character} corresponds to a Unicode @defterm{scalar
|
||||
A Racket @deftech{character} corresponds to a Unicode @defterm{scalar
|
||||
value}. Roughly, a scalar value is an unsigned integer whose
|
||||
representation fits into 21 bits, and that maps to some notion of a
|
||||
natural-language character or piece of a character. Technically, a
|
||||
|
@ -14,17 +14,17 @@ scalar value is a simpler notion than the concept called a
|
|||
works well for many purposes. For example, any accented Roman letter
|
||||
can be represented as a scalar value, as can any common Chinese character.
|
||||
|
||||
Although each Scheme character corresponds to an integer, the
|
||||
Although each Racket character corresponds to an integer, the
|
||||
character datatype is separate from numbers. The
|
||||
@scheme[char->integer] and @scheme[integer->char] procedures convert
|
||||
@racket[char->integer] and @racket[integer->char] procedures convert
|
||||
between scalar-value numbers and the corresponding character.
|
||||
|
||||
A printable character normally prints as @litchar{#\} followed
|
||||
by the represented character. An unprintable character normally prints
|
||||
as @litchar{#\u} followed by the scalar value as hexadecimal
|
||||
number. A few characters are printed specially; for example, the space
|
||||
and linefeed characters print as @scheme[#\space] and
|
||||
@scheme[#\newline], respectively.
|
||||
and linefeed characters print as @racket[#\space] and
|
||||
@racket[#\newline], respectively.
|
||||
|
||||
@refdetails/gory["parse-character"]{the syntax of characters}
|
||||
|
||||
|
@ -32,12 +32,12 @@ and linefeed characters print as @scheme[#\space] and
|
|||
(integer->char 65)
|
||||
(char->integer #\A)
|
||||
#\u03BB
|
||||
(eval:alts @#,schemevalfont["#\\u03BB"] #\u03BB)
|
||||
(eval:alts @#,racketvalfont["#\\u03BB"] #\u03BB)
|
||||
(integer->char 17)
|
||||
(char->integer #\space)
|
||||
]
|
||||
|
||||
The @scheme[display] procedure directly writes a character to the
|
||||
The @racket[display] procedure directly writes a character to the
|
||||
current output port (see @secref["i/o"]), in contrast to the
|
||||
character-constant syntax used to print a character result.
|
||||
|
||||
|
@ -46,7 +46,7 @@ character-constant syntax used to print a character result.
|
|||
(display #\A)
|
||||
]
|
||||
|
||||
Scheme provides several classification and conversion procedures on
|
||||
Racket provides several classification and conversion procedures on
|
||||
characters. Beware, however, that conversions on some Unicode
|
||||
characters work as a human would expect only when they are in a string
|
||||
(e.g., upcasing ``@elem["\uDF"]'' or downcasing ``@elem["\u03A3"]'').
|
||||
|
@ -59,10 +59,10 @@ characters work as a human would expect only when they are in a string
|
|||
(char-upcase #\uDF)
|
||||
]
|
||||
|
||||
The @scheme[char=?] procedure compares two or more characters, and
|
||||
@scheme[char-ci=?] compares characters ignoring case. The
|
||||
@scheme[eqv?] and @scheme[equal?] procedures behave the same as
|
||||
@scheme[char=?] on characters; use @scheme[char=?] when you want to
|
||||
The @racket[char=?] procedure compares two or more characters, and
|
||||
@racket[char-ci=?] compares characters ignoring case. The
|
||||
@racket[eqv?] and @racket[equal?] procedures behave the same as
|
||||
@racket[char=?] on characters; use @racket[char=?] when you want to
|
||||
more specifically declare that the values being compared are
|
||||
characters.
|
||||
|
||||
|
|
|
@ -5,18 +5,18 @@
|
|||
|
||||
@title[#:tag "conditionals"]{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
|
||||
Most functions used for branching, such as @racket[<] and
|
||||
@racket[string?], produce either @racket[#t] or @racket[#f]. Racket's
|
||||
branching forms, however, treat any value other than @racket[#f] as
|
||||
true. We say a @defterm{true value} to mean any value other than
|
||||
@scheme[#f].
|
||||
@racket[#f].
|
||||
|
||||
This convention for ``true value'' meshes well with protocols where
|
||||
@scheme[#f] can serve as failure or to indicate that an optional value
|
||||
@racket[#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
|
||||
For example, the @racket[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:
|
||||
|
@ -33,46 +33,46 @@ list:
|
|||
]
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Simple Branching: @scheme[if]}
|
||||
@section{Simple Branching: @racket[if]}
|
||||
|
||||
@refalso["if"]{@scheme[if]}
|
||||
@refalso["if"]{@racket[if]}
|
||||
|
||||
In an @scheme[if] form,
|
||||
In an @racket[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.
|
||||
the @racket[_test-expr] is always evaluated. If it produces any value
|
||||
other than @racket[#f], then @racket[_then-expr] is
|
||||
evaluated. Otherwise, @racket[_else-expr] is evaluated.
|
||||
|
||||
An @scheme[if] form must have both a @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["begin"].
|
||||
An @racket[if] form must have both a @racket[_then-expr] and an
|
||||
@racket[_else-expr]; the latter is not optional. To perform (or skip)
|
||||
side-effects based on a @racket[_test-expr], use @racket[when] or
|
||||
@racket[unless], which we describe later in @secref["begin"].
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "and+or"]{Combining Tests: @scheme[and] and @scheme[or]}
|
||||
@section[#:tag "and+or"]{Combining Tests: @racket[and] and @racket[or]}
|
||||
|
||||
@refalso["if"]{@scheme[and] and @scheme[or]}
|
||||
@refalso["if"]{@racket[and] and @racket[or]}
|
||||
|
||||
Scheme's @scheme[and] and @scheme[or] are syntactic forms, rather than
|
||||
functions. Unlike a function, the @scheme[and] and @scheme[or] forms
|
||||
Racket's @racket[and] and @racket[or] are syntactic forms, rather than
|
||||
functions. Unlike a function, the @racket[and] and @racket[or] forms
|
||||
can skip evaluation of later expressions if an earlier one determines
|
||||
the answer.
|
||||
|
||||
@specform[(and expr ...)]
|
||||
|
||||
An @scheme[and] 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].
|
||||
An @racket[and] form produces @racket[#f] if any of its @racket[_expr]s
|
||||
produces @racket[#f]. Otherwise, it produces the value of its last
|
||||
@racket[_expr]. As a special case, @racket[(and)] produces
|
||||
@racket[#t].
|
||||
|
||||
@specform[(or expr ...)]
|
||||
|
||||
The @scheme[or] form produces @scheme[#f] if all of its
|
||||
@scheme[_expr]s produce @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].
|
||||
The @racket[or] form produces @racket[#f] if all of its
|
||||
@racket[_expr]s produce @racket[#f]. Otherwise, it produces the first
|
||||
non-@racket[#f] value from its @racket[expr]s. As a special case,
|
||||
@racket[(or)] produces @racket[#f].
|
||||
|
||||
@examples[
|
||||
(code:line
|
||||
|
@ -84,39 +84,39 @@ non-@scheme[#f] value from its @scheme[expr]s. As a special case,
|
|||
(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.
|
||||
If evaluation reaches the last @racket[_expr] of an @racket[and] or
|
||||
@racket[or] form, then the @racket[_expr]'s value directly determines
|
||||
the @racket[and] or @racket[or] result. Therefore, the last
|
||||
@racket[_expr] is in tail position, which means that the above
|
||||
@racket[got-milk?] function runs in constant space.
|
||||
|
||||
@guideother{@secref["tail-recursion"] introduces tail calls and tail positions.}
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "cond"]{Chaining Tests: @scheme[cond]}
|
||||
@section[#:tag "cond"]{Chaining Tests: @racket[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
|
||||
The @racket[cond] form chains a series of tests to select a result
|
||||
expression. To a first approximation, the syntax of @racket[cond] is
|
||||
as follows:
|
||||
|
||||
@refalso["if"]{@scheme[cond]}
|
||||
@refalso["if"]{@racket[cond]}
|
||||
|
||||
@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.
|
||||
Each @racket[_test-expr] is evaluated in order. If it produces
|
||||
@racket[#f], the corresponding @racket[_expr]s are ignored, and
|
||||
evaluation proceeds to the next @racket[_test-expr]. As soon as a
|
||||
@racket[_test-expr] produces a true value, its @racket[_text-expr]s
|
||||
are evaluated to produce the result for the @racket[cond] form, and no
|
||||
further @racket[_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
|
||||
The last @racket[_test-expr] in a @racket[cond] can be replaced by
|
||||
@racket[else]. In terms of evaluation, @racket[else] serves as a
|
||||
synonym for @racket[#t], but it clarifies that the last clause is
|
||||
meant to catch all remaining cases. If @racket[else] is not used, then
|
||||
it is possible that no @racket[_test-expr]s produce a true value; in
|
||||
that case, the result of the @racket[cond] expression is
|
||||
@|void-const|.
|
||||
|
||||
@examples[
|
||||
|
@ -140,7 +140,7 @@ that case, the result of the @scheme[cond] expression is
|
|||
(got-milk? '(apple milk banana))
|
||||
]
|
||||
|
||||
The full syntax of @scheme[cond] includes two more kinds of clauses:
|
||||
The full syntax of @racket[cond] includes two more kinds of clauses:
|
||||
|
||||
@specform/subs[#:literals (else =>)
|
||||
(cond cond-clause ...)
|
||||
|
@ -149,9 +149,9 @@ The full syntax of @scheme[cond] includes two more kinds of clauses:
|
|||
[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.
|
||||
The @racket[=>] variant captures the true result of its
|
||||
@racket[_test-expr] and passes it to the result of the
|
||||
@racket[_proc-expr], which must be a function of one argument.
|
||||
|
||||
@examples[
|
||||
(define (after-groucho lst)
|
||||
|
@ -163,6 +163,6 @@ The @scheme[=>] variant captures the true result of its
|
|||
(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.
|
||||
A clause that includes only a @racket[_test-expr] is rarely used. It
|
||||
captures the true result of the @racket[_test-expr], and simply
|
||||
returns the result for the whole @racket[cond] expression.
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
scribble/eval
|
||||
"guide-utils.ss"
|
||||
"contracts-utils.ss"
|
||||
(for-label scheme/contract)
|
||||
(for-label scheme/gui))
|
||||
(for-label racket/contract)
|
||||
(for-label racket/gui))
|
||||
|
||||
@title[#:tag "contracts-examples"]{Examples}
|
||||
|
||||
This section illustrates the current state of PLT Scheme's contract
|
||||
This section illustrates the current state of Racket's contract
|
||||
implementation with a series of examples from @italic{Design by
|
||||
Contract, by Example} @cite["Mitchell02"].
|
||||
|
||||
|
@ -51,8 +51,8 @@ Each of the following sections corresponds to a chapter in
|
|||
|
||||
Mitchell and McKim use Eiffel as the underlying programming language and
|
||||
employ a conventional imperative programming style. Our long-term goal is
|
||||
to transliterate their examples into applicative Scheme,
|
||||
structure-oriented imperative Scheme, and PLT Scheme's class system.
|
||||
to transliterate their examples into applicative Racket,
|
||||
structure-oriented imperative Racket, and Racket's class system.
|
||||
|
||||
Note: To mimic Mitchell and McKim's informal notion of parametericity
|
||||
(parametric polymorphism), we use first-class contracts. At several
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
"guide-utils.ss"
|
||||
"contracts-utils.ss"
|
||||
(for-label framework/framework)
|
||||
(for-label scheme/contract)
|
||||
(for-label scheme/gui))
|
||||
(for-label racket/contract)
|
||||
(for-label racket/gui))
|
||||
|
||||
@title[#:tag "contracts-general-functions"]{Contracts on Functions in General}
|
||||
|
||||
|
@ -14,8 +14,8 @@
|
|||
You wrote your module. You added contracts. You put them into the interface
|
||||
so that client programmers have all the information from interfaces. It's a
|
||||
piece of art:
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
|
||||
(provide/contract
|
||||
[deposit (-> (lambda (x)
|
||||
|
@ -30,24 +30,24 @@ Several clients used your module. Others used their
|
|||
modules in turn. And all of a sudden one of them sees this error
|
||||
message:
|
||||
|
||||
@inset-flow{@schemeerror{bank-client broke the contract (-> ??? any)
|
||||
@inset-flow{@racketerror{bank-client broke the contract (-> ??? any)
|
||||
it had with myaccount on deposit; expected <???>, given: -10}}
|
||||
|
||||
Clearly, @scheme[bank-client] is a module that uses @scheme[myaccount]
|
||||
but what is the @schemeerror{???} doing there? Wouldn't it be nice if
|
||||
Clearly, @racket[bank-client] is a module that uses @racket[myaccount]
|
||||
but what is the @racketerror{???} doing there? Wouldn't it be nice if
|
||||
we had a name for this class of data much like we have string, number,
|
||||
and so on?
|
||||
|
||||
For this situation, PLT Scheme provides @deftech{flat named
|
||||
For this situation, Racket provides @deftech{flat named
|
||||
contracts}. The use of ``contract'' in this term shows that contracts
|
||||
are first-class values. The ``flat'' means that the collection of data
|
||||
is a subset of the built-in atomic classes of data; they are described
|
||||
by a predicate that consumes all Scheme values and produces a
|
||||
by a predicate that consumes all Racket values and produces a
|
||||
boolean. The ``named'' part says what we want to do, which is to name
|
||||
the contract so that error messages become intelligible:
|
||||
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
|
||||
(define (amount? x) (and (number? x) (integer? x) (>= x 0)))
|
||||
(define amount (flat-named-contract 'amount amount?))
|
||||
|
@ -62,16 +62,16 @@ scheme
|
|||
With this little change, the error message becomes all of the
|
||||
sudden quite readable:
|
||||
|
||||
@inset-flow{@schemeerror{bank-client broke the contract (-> amount
|
||||
@inset-flow{@racketerror{bank-client broke the contract (-> amount
|
||||
any) it had with myaccount on deposit; expected <amount>, given: -10}}
|
||||
|
||||
@ctc-section[#:tag "optional"]{Optional Arguments}
|
||||
|
||||
Take a look at this excerpt from a string-processing module, inspired by the
|
||||
@link["http://schemecookbook.org"]{Scheme cookbook}:
|
||||
@link["http://racketcookbook.org"]{Racket cookbook}:
|
||||
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
|
||||
(provide/contract
|
||||
(code:comment @#,t{pad the given str left and right with})
|
||||
|
@ -89,28 +89,28 @@ scheme
|
|||
(build-string rmargin (λ (x) pad))))
|
||||
]
|
||||
|
||||
The module exports @scheme[string-pad-center], a function
|
||||
that creates a string of a given @scheme[width] with the
|
||||
The module exports @racket[string-pad-center], a function
|
||||
that creates a string of a given @racket[width] with the
|
||||
given string in the center. The default fill character is
|
||||
@scheme[#\space]; if the client module wishes to use a
|
||||
different character, it may call @scheme[string-pad-center]
|
||||
with a third argument, a @scheme[char], overwriting the
|
||||
@racket[#\space]; if the client module wishes to use a
|
||||
different character, it may call @racket[string-pad-center]
|
||||
with a third argument, a @racket[char], overwriting the
|
||||
default.
|
||||
|
||||
The function definition uses optional arguments, which is
|
||||
appropriate for this kind of functionality. The interesting
|
||||
point here is the formulation of the contract for the
|
||||
@scheme[string-pad-center].
|
||||
@racket[string-pad-center].
|
||||
|
||||
|
||||
The contract combinator @scheme[->*], demands several groups of contracts:
|
||||
The contract combinator @racket[->*], demands several groups of contracts:
|
||||
@itemize[
|
||||
@item{The first one is a parenthesized group of contracts for all required
|
||||
arguments. In this example, we see two: @scheme[string?] and
|
||||
@scheme[natural-number/c]. }
|
||||
arguments. In this example, we see two: @racket[string?] and
|
||||
@racket[natural-number/c]. }
|
||||
|
||||
@item{The second one is a parenthesized group of contracts for all optional
|
||||
arguments: @scheme[char?]. }
|
||||
arguments: @racket[char?]. }
|
||||
|
||||
@item{The last one is a single contract: the result of the function.}
|
||||
]
|
||||
|
@ -123,41 +123,41 @@ arguments: @scheme[char?]. }
|
|||
|
||||
@ctc-section[#:tag "rest-args"]{Rest Arguments}
|
||||
|
||||
We all know that @scheme[+] in Beginner Scheme is a function
|
||||
We all know that @racket[+] in Beginner Racket is a function
|
||||
that consumes at least two numbers but, in principle,
|
||||
arbitrarily many more. Defining the function is easy:
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define (plus fst snd . rst)
|
||||
(foldr + (+ fst snd) rst))
|
||||
]
|
||||
Describing this function via a contract is difficult because of the rest
|
||||
argument (@scheme[rst]).
|
||||
argument (@racket[rst]).
|
||||
|
||||
Here is the contract:
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(provide/contract
|
||||
[plus (->* (number? number?) () #:rest (listof number?) number?)])
|
||||
]
|
||||
The @scheme[->*] contract combinator empowers you to specify
|
||||
The @racket[->*] contract combinator empowers you to specify
|
||||
functions that consume a variable number of arguments or functions like
|
||||
@scheme[plus], which consume ``at least this number'' of arguments but
|
||||
@racket[plus], which consume ``at least this number'' of arguments but
|
||||
an arbitrary number of additional arguments.
|
||||
|
||||
The contracts for the required arguments are enclosed in the first
|
||||
pair of parentheses:
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(number? number?)
|
||||
]
|
||||
|
||||
For @scheme[plus] they demand two numbers. The empty pair of
|
||||
For @racket[plus] they demand two numbers. The empty pair of
|
||||
parenthesis indicates that there are no optional arguments
|
||||
(not counting the rest arguments) and the contract for the
|
||||
rest argument follows @scheme[#:rest]
|
||||
@schemeblock[
|
||||
rest argument follows @racket[#:rest]
|
||||
@racketblock[
|
||||
(listof number?)
|
||||
]
|
||||
Since the remainder of the actual arguments are collected
|
||||
in a list for a rest parameter such as @scheme[rst], the
|
||||
in a list for a rest parameter such as @racket[rst], the
|
||||
contract demands a list of values; in this specific
|
||||
examples, these values must be numbers.
|
||||
|
||||
|
@ -165,12 +165,12 @@ rest argument follows @scheme[#:rest]
|
|||
|
||||
Sometimes, a function accepts many arguments and remembering
|
||||
their order can be a nightmare. To help with such functions,
|
||||
PLT Scheme has @seclink["lambda-keywords"]{keyword} arguments.
|
||||
Racket has @seclink["lambda-keywords"]{keyword} arguments.
|
||||
|
||||
For example, consider this function that creates a simple
|
||||
GUI and asks the user a yes-or-no question:
|
||||
@schememod[
|
||||
scheme/gui
|
||||
@racketmod[
|
||||
racket/gui
|
||||
|
||||
(define (ask-yes-or-no-question #:question question
|
||||
#:default answer
|
||||
|
@ -203,31 +203,31 @@ scheme/gui
|
|||
]
|
||||
@margin-note{Note that if you really want to ask a yes-or-no
|
||||
question via a GUI, you should use
|
||||
@scheme[message-box/custom] (and generally speaking,
|
||||
@racket[message-box/custom] (and generally speaking,
|
||||
avoiding the responses ``yes'' and ``no'' in your dialog is a
|
||||
good idea, too ...).}
|
||||
|
||||
The contract for @scheme[ask-yes-or-no-question] uses our
|
||||
old friend the @scheme[->] contract combinator. Just like
|
||||
@scheme[lambda] (or @scheme[define]-based functions) use
|
||||
The contract for @racket[ask-yes-or-no-question] uses our
|
||||
old friend the @racket[->] contract combinator. Just like
|
||||
@racket[lambda] (or @racket[define]-based functions) use
|
||||
keywords for specifying keyword arguments, it uses keywords
|
||||
for specifying contracts on keyword arguments. In this case,
|
||||
it says that @scheme[ask-yes-or-no-question] must receive
|
||||
it says that @racket[ask-yes-or-no-question] must receive
|
||||
five keyword arguments, one for each of the keywords
|
||||
@scheme[#:question],
|
||||
@scheme[#:default],
|
||||
@scheme[#:title],
|
||||
@scheme[#:width], and
|
||||
@scheme[#:height].
|
||||
@racket[#:question],
|
||||
@racket[#:default],
|
||||
@racket[#:title],
|
||||
@racket[#:width], and
|
||||
@racket[#:height].
|
||||
Also, just like in a function definition, the keywords in
|
||||
the @scheme[->] may appear in any order.
|
||||
the @racket[->] may appear in any order.
|
||||
|
||||
@ctc-section[#:tag "optional-keywords"]{Optional Keyword Arguments}
|
||||
|
||||
Of course, many of the parameters in
|
||||
@scheme[ask-yes-or-no-question] (from the previous question)
|
||||
@racket[ask-yes-or-no-question] (from the previous question)
|
||||
have reasonable defaults, and should be made optional:
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define (ask-yes-or-no-question #:question question
|
||||
#:default answer
|
||||
#:title [title "Yes or No?"]
|
||||
|
@ -237,14 +237,14 @@ have reasonable defaults, and should be made optional:
|
|||
]
|
||||
|
||||
To specify this function's contract, we need to use
|
||||
@scheme[->*]. It too supports keywords just as you might
|
||||
@racket[->*]. It too supports keywords just as you might
|
||||
expect, in both the optional and mandatory argument
|
||||
sections. In this case, we have mandatory keywords
|
||||
@scheme[#:question] and @scheme[#:default], and optional keywords
|
||||
@scheme[#:title],
|
||||
@scheme[#:width], and
|
||||
@scheme[#:height]. So, we write the contract like this:
|
||||
@schemeblock[
|
||||
@racket[#:question] and @racket[#:default], and optional keywords
|
||||
@racket[#:title],
|
||||
@racket[#:width], and
|
||||
@racket[#:height]. So, we write the contract like this:
|
||||
@racketblock[
|
||||
(provide/contract
|
||||
[ask-yes-or-no-question
|
||||
(->* (#:question string?
|
||||
|
@ -263,8 +263,8 @@ optional ones in the second section.
|
|||
|
||||
Here is an excerpt from an imaginary (pardon the pun) numerics module:
|
||||
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
(provide/contract
|
||||
[sqrt.v1 (->d ([argument (>=/c 1)])
|
||||
()
|
||||
|
@ -272,22 +272,22 @@ scheme
|
|||
...
|
||||
]
|
||||
|
||||
The contract for the exported function @scheme[sqrt.v1] uses the
|
||||
@scheme[->d] rather than @scheme[->] function contract. The ``d''
|
||||
The contract for the exported function @racket[sqrt.v1] uses the
|
||||
@racket[->d] rather than @racket[->] function contract. The ``d''
|
||||
stands for @italic{dependent} contract, meaning the contract for the
|
||||
function range depends on the value of the argument.
|
||||
|
||||
In this particular case, the argument of @scheme[sqrt.v1] is greater
|
||||
In this particular case, the argument of @racket[sqrt.v1] is greater
|
||||
or equal to 1. Hence a very basic correctness check is that the result is
|
||||
smaller than the argument. (Naturally, if this function is critical, one
|
||||
could strengthen this check with additional clauses.)
|
||||
|
||||
In general, a dependent function contract looks just like
|
||||
the more general @scheme[->*] contract, but with names added
|
||||
the more general @racket[->*] contract, but with names added
|
||||
that can be used elsewhere in the contract.
|
||||
|
||||
Yes, there are many other contract combinators such as @scheme[<=/c]
|
||||
and @scheme[>=/c], and it pays off to look them up in the contract
|
||||
Yes, there are many other contract combinators such as @racket[<=/c]
|
||||
and @racket[>=/c], and it pays off to look them up in the contract
|
||||
section of the reference manual. They simplify contracts tremendously
|
||||
and make them more accessible to potential clients.
|
||||
|
||||
|
@ -299,14 +299,14 @@ course, ordinary accounts don't let customers withdraw an arbitrary amount of
|
|||
money but only as much as they have in the account.
|
||||
|
||||
Suppose the account module provides the following two functions:
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
balance : (-> account amount)
|
||||
withdraw : (-> account amount account)
|
||||
]
|
||||
Then, informally, the proper precondition for @scheme[withdraw] is that
|
||||
Then, informally, the proper precondition for @racket[withdraw] is that
|
||||
``the balance of the given account is greater than or equal to the given (withdrawal) amount.''
|
||||
The postcondition is similar to the one for
|
||||
@ctc-link["flat-named-contracts"]{@scheme[deposit]}:
|
||||
@ctc-link["flat-named-contracts"]{@racket[deposit]}:
|
||||
``the balance of the resulting account is larger than (or equal to) the one of the
|
||||
given account.''
|
||||
You could of course also formulate a full-fledged correctness condition, namely,
|
||||
|
@ -315,8 +315,8 @@ one, plus the given amount.
|
|||
|
||||
The following module implements accounts imperatively and specifies the
|
||||
conditions we just discussed:
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
|
||||
(code:comment "section 1: the contract definitions")
|
||||
(define-struct account (balance) #:mutable)
|
||||
|
@ -359,36 +359,36 @@ scheme
|
|||
]
|
||||
|
||||
The second section is the export interface: @itemize[
|
||||
@item{@scheme[create] consumes an initial deposit and
|
||||
@item{@racket[create] consumes an initial deposit and
|
||||
produces an account. This kind of contract is just like a
|
||||
type in a statically typed language, except that statically
|
||||
typed languages usually don't support the type ``natural
|
||||
numbers'' (as a full-fledged subtype of numbers). }
|
||||
|
||||
@item{@scheme[balance] consumes an account and computes its current balance.}
|
||||
@item{@racket[balance] consumes an account and computes its current balance.}
|
||||
|
||||
@item{@scheme[withdraw] consumes an account, named @scheme[acc], and an
|
||||
amount, @scheme[amt]. In addition to being an @scheme[amount], the
|
||||
latter must also be less than @scheme[(balance acc)], i.e., the balance of
|
||||
the given account. That is, the contract for @scheme[amt] depends on the
|
||||
value of @scheme[acc], which is what the @scheme[->d]
|
||||
@item{@racket[withdraw] consumes an account, named @racket[acc], and an
|
||||
amount, @racket[amt]. In addition to being an @racket[amount], the
|
||||
latter must also be less than @racket[(balance acc)], i.e., the balance of
|
||||
the given account. That is, the contract for @racket[amt] depends on the
|
||||
value of @racket[acc], which is what the @racket[->d]
|
||||
contract combinator expresses.
|
||||
|
||||
The result contract is formed on the fly:
|
||||
@scheme[(mk-account-contract acc amt > msg>)].
|
||||
@racket[(mk-account-contract acc amt > msg>)].
|
||||
It is an application of a contract-producing function that
|
||||
consumes an account, an amount, a comparison operator, and an error message (a
|
||||
format string). The result is a contract.
|
||||
}
|
||||
|
||||
@item{@scheme[deposit]'s contract has been reformulated using the
|
||||
@scheme[->d] combinator. }
|
||||
@item{@racket[deposit]'s contract has been reformulated using the
|
||||
@racket[->d] combinator. }
|
||||
]
|
||||
|
||||
The code in the first section defines all those pieces that
|
||||
are needed for the formulation of the export contracts:
|
||||
@scheme[account?], @scheme[amount], error messages (format
|
||||
strings), and @scheme[mk-account-contract]. The latter is a
|
||||
@racket[account?], @racket[amount], error messages (format
|
||||
strings), and @racket[mk-account-contract]. The latter is a
|
||||
function that extracts the current balance from the given
|
||||
account and then returns a named contract, whose error
|
||||
message (contract name) is a string that refers to this
|
||||
|
@ -398,12 +398,12 @@ given comparison operator, than the original balance.
|
|||
|
||||
@ctc-section[#:tag "arrow-d-eval-order"]{Ensuring that a Function Properly Modifies State}
|
||||
|
||||
The @scheme[->d] contract combinator can also ensure that a
|
||||
The @racket[->d] contract combinator can also ensure that a
|
||||
function only modifies state according to certain
|
||||
constraints. For example, consider this contract
|
||||
(it is a slightly simplified from the function
|
||||
@scheme[preferences:add-panel] in the framework):
|
||||
@schemeblock[
|
||||
@racket[preferences:add-panel] in the framework):
|
||||
@racketblock[
|
||||
(->d ([parent (is-a?/c area-container-window<%>)])
|
||||
()
|
||||
[_
|
||||
|
@ -414,29 +414,29 @@ constraints. For example, consider this contract
|
|||
(send parent get-children))))])
|
||||
]
|
||||
It says that the function accepts a single argument, named
|
||||
@scheme[parent], and that @scheme[parent] must be
|
||||
an object matching the interface @scheme[area-container-window<%>].
|
||||
@racket[parent], and that @racket[parent] must be
|
||||
an object matching the interface @racket[area-container-window<%>].
|
||||
|
||||
The range contract ensures that the function only modifies
|
||||
the children of @scheme[parent] by adding a new child to the
|
||||
the children of @racket[parent] by adding a new child to the
|
||||
front of the list. It accomplishes this by using the
|
||||
@scheme[_] instead of a normal identifier, which tells the
|
||||
@racket[_] instead of a normal identifier, which tells the
|
||||
contract library that the range contract does not depend on
|
||||
the values of any of the results, and thus the contract
|
||||
library evaluates the expression following the @scheme[_]
|
||||
library evaluates the expression following the @racket[_]
|
||||
when the function is called, instead of when it
|
||||
returns. Therefore the call to the @scheme[get-children] method
|
||||
returns. Therefore the call to the @racket[get-children] method
|
||||
happens before the function under the contract is called.
|
||||
When the function under contract returns, its result is
|
||||
passed in as @scheme[child], and the contract ensures that
|
||||
passed in as @racket[child], and the contract ensures that
|
||||
the children after the function return are the same as the
|
||||
children before the function called, but with one more
|
||||
child, at the front of the list.
|
||||
|
||||
To see the difference in a toy example that focuses
|
||||
on this point, consider this program
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
(define x '())
|
||||
(define (get-x) x)
|
||||
(define (f) (set! x (cons 'f x)))
|
||||
|
@ -444,29 +444,29 @@ scheme
|
|||
[f (->d () () [_ (begin (set! x (cons 'ctc x)) any/c)])]
|
||||
[get-x (-> (listof symbol?))])
|
||||
]
|
||||
If you were to require this module, call @scheme[f], then
|
||||
the result of @scheme[get-x] would be @scheme['(f ctc)]. In
|
||||
contrast, if the contract for @scheme[f] were
|
||||
@schemeblock[(->d () () [res (begin (set! x (cons 'ctc x)) any/c)])]
|
||||
(only changing the underscore to @scheme[res]), then
|
||||
the result of @scheme[get-x] would be @scheme['(ctc f)].
|
||||
If you were to require this module, call @racket[f], then
|
||||
the result of @racket[get-x] would be @racket['(f ctc)]. In
|
||||
contrast, if the contract for @racket[f] were
|
||||
@racketblock[(->d () () [res (begin (set! x (cons 'ctc x)) any/c)])]
|
||||
(only changing the underscore to @racket[res]), then
|
||||
the result of @racket[get-x] would be @racket['(ctc f)].
|
||||
|
||||
@ctc-section[#:tag "case-lambda"]{Contracts for @scheme[case-lambda]}
|
||||
@ctc-section[#:tag "case-lambda"]{Contracts for @racket[case-lambda]}
|
||||
|
||||
Dybvig, in Chapter 5 of the
|
||||
@link["http://www.scheme.com/csug/"]{Chez Scheme User's Guide},
|
||||
@link["http://www.racket.com/csug/"]{Chez Racket User's Guide},
|
||||
explains the meaning and pragmatics of
|
||||
@scheme[case-lambda] with the following example (among
|
||||
@racket[case-lambda] with the following example (among
|
||||
others):
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define substring1
|
||||
(case-lambda
|
||||
[(s) (substring1 s 0 (string-length s))]
|
||||
[(s start) (substring1 s start (string-length s))]
|
||||
[(s start end) (substring s start end)]))
|
||||
]
|
||||
This version of @scheme[substring] has one of the following signature:
|
||||
This version of @racket[substring] has one of the following signature:
|
||||
@itemize[
|
||||
@item{just a string, in which case it copies the string;}
|
||||
@item{a string and an index into the string, in which case it extracts the
|
||||
|
@ -475,9 +475,9 @@ others):
|
|||
fragment of the string between the two indices. }
|
||||
]
|
||||
|
||||
The contract for such a function is formed with the @scheme[case->]
|
||||
The contract for such a function is formed with the @racket[case->]
|
||||
combinator, which combines as many functional contracts as needed:
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(provide/contract
|
||||
[substring1
|
||||
(case->
|
||||
|
@ -485,19 +485,19 @@ The contract for such a function is formed with the @scheme[case->]
|
|||
(string? natural-number/c . -> . string?)
|
||||
(string? natural-number/c natural-number/c . -> . string?))])
|
||||
]
|
||||
As you can see, the contract for @scheme[substring1] combines three
|
||||
As you can see, the contract for @racket[substring1] combines three
|
||||
function contracts, just as many clauses as the explanation of its
|
||||
functionality required.
|
||||
|
||||
@;{
|
||||
This isn't supported anymore (yet...?). -robby
|
||||
|
||||
In the case of @scheme[substring1], we also know that the indices
|
||||
In the case of @racket[substring1], we also know that the indices
|
||||
that it consumes ought to be natural numbers less than the length of the
|
||||
given string. Since @scheme[case->] just combines arrow contracts,
|
||||
given string. Since @racket[case->] just combines arrow contracts,
|
||||
adding such constraints is just a matter of strengthening the individual
|
||||
contracts:
|
||||
<scheme>
|
||||
<racket>
|
||||
(provide/contract
|
||||
[substring1 (case->
|
||||
(string? . -> . string?)
|
||||
|
@ -510,17 +510,17 @@ In the case of @scheme[substring1], we also know that the indices
|
|||
(>=/c a)
|
||||
(</c (string-length s)))])
|
||||
string?))])
|
||||
</scheme>
|
||||
Here we used @scheme[->r] to name the parameters and express the
|
||||
</racket>
|
||||
Here we used @racket[->r] to name the parameters and express the
|
||||
numeric constraints on them.
|
||||
}
|
||||
|
||||
@ctc-section[#:tag "multiple"]{Multiple Result Values}
|
||||
|
||||
The function @scheme[split] consumes a list of @scheme[char]s
|
||||
The function @racket[split] consumes a list of @racket[char]s
|
||||
and delivers the string that occurs before the first occurrence of
|
||||
@scheme[#\newline] (if any) and the rest of the list:
|
||||
@schemeblock[
|
||||
@racket[#\newline] (if any) and the rest of the list:
|
||||
@racketblock[
|
||||
(define (split l)
|
||||
(define (split l w)
|
||||
(cond
|
||||
|
@ -534,18 +534,18 @@ The function @scheme[split] consumes a list of @scheme[char]s
|
|||
traversing a single list.
|
||||
|
||||
The contract for such a function can use the ordinary
|
||||
function arrow @scheme[->], since it
|
||||
treats @scheme[values] specially, when it appears as the
|
||||
function arrow @racket[->], since it
|
||||
treats @racket[values] specially, when it appears as the
|
||||
last result:
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(provide/contract
|
||||
[split (-> (listof char?)
|
||||
(values string? (listof char?)))])
|
||||
]
|
||||
|
||||
The contract for such a function can also be written
|
||||
using @scheme[->*], just like @scheme[plus]:
|
||||
@schemeblock[
|
||||
using @racket[->*], just like @racket[plus]:
|
||||
@racketblock[
|
||||
(provide/contract
|
||||
[split (->* ((listof char?))
|
||||
()
|
||||
|
@ -555,13 +555,13 @@ using @scheme[->*], just like @scheme[plus]:
|
|||
extra pair of parentheses (and must always be wrapped like
|
||||
that) and the empty pair of parentheses indicates that
|
||||
there are no optoinal arguments. The contracts for the
|
||||
results are inside @scheme[values]: a string and a list of
|
||||
results are inside @racket[values]: a string and a list of
|
||||
characters.
|
||||
|
||||
Now suppose we also want to ensure that the first result of
|
||||
@scheme[split] is a prefix of the given word in list format. In that
|
||||
case, we need to use the @scheme[->d] contract combinator:
|
||||
@schemeblock[
|
||||
@racket[split] is a prefix of the given word in list format. In that
|
||||
case, we need to use the @racket[->d] contract combinator:
|
||||
@racketblock[
|
||||
(define (substring-of? s)
|
||||
(flat-named-contract
|
||||
(format "substring of ~s" s)
|
||||
|
@ -576,24 +576,24 @@ Now suppose we also want to ensure that the first result of
|
|||
(values [s (substring-of (list->string fl))]
|
||||
[c (listof char?)]))])
|
||||
]
|
||||
Like @scheme[->*], the @scheme[->d] combinator uses a function over the
|
||||
Like @racket[->*], the @racket[->d] combinator uses a function over the
|
||||
argument to create the range contracts. Yes, it doesn't just return one
|
||||
contract but as many as the function produces values: one contract per
|
||||
value. In this case, the second contract is the same as before, ensuring
|
||||
that the second result is a list of @scheme[char]s. In contrast, the
|
||||
that the second result is a list of @racket[char]s. In contrast, the
|
||||
first contract strengthens the old one so that the result is a prefix of
|
||||
the given word.
|
||||
|
||||
This contract is expensive to check of course. Here is a slightly
|
||||
cheaper version:
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(provide/contract
|
||||
[split (->d ([fl (listof char?)])
|
||||
()
|
||||
(values [s (string-len/c (length fl))]
|
||||
[c (listof char?)]))])
|
||||
]
|
||||
Click on @scheme[string-len/c] to see what it does.
|
||||
Click on @racket[string-len/c] to see what it does.
|
||||
|
||||
@ctc-section[#:tag "no-domain"]{Procedures of Some Fixed, but Statically Unknown Arity}
|
||||
|
||||
|
@ -602,8 +602,8 @@ function and a list of numbers that eventually applies the former to the
|
|||
latter. Unless the arity of the given function matches the length of the
|
||||
given list, your procedure is in trouble.
|
||||
|
||||
Consider this @scheme[n-step] function:
|
||||
@schemeblock[
|
||||
Consider this @racket[n-step] function:
|
||||
@racketblock[
|
||||
(code:comment "(number ... -> (union #f number?)) (listof number) -> void")
|
||||
(define (n-step proc inits)
|
||||
(let ([inc (apply proc inits)])
|
||||
|
@ -611,15 +611,15 @@ Consider this @scheme[n-step] function:
|
|||
(n-step proc (map (λ (x) (+ x inc)) inits)))))
|
||||
]
|
||||
|
||||
The argument of @scheme[n-step] is @scheme[proc], a function
|
||||
@scheme[proc] whose results are either numbers or false, and a list. It
|
||||
then applies @scheme[proc] to the list @scheme[inits]. As long as
|
||||
@scheme[proc] returns a number, @scheme[n-step] treats that number
|
||||
as an increment for each of the numbers in @scheme[inits] and
|
||||
recurs. When @scheme[proc] returns @scheme[false], the loop stops.
|
||||
The argument of @racket[n-step] is @racket[proc], a function
|
||||
@racket[proc] whose results are either numbers or false, and a list. It
|
||||
then applies @racket[proc] to the list @racket[inits]. As long as
|
||||
@racket[proc] returns a number, @racket[n-step] treats that number
|
||||
as an increment for each of the numbers in @racket[inits] and
|
||||
recurs. When @racket[proc] returns @racket[false], the loop stops.
|
||||
|
||||
Here are two uses:
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(code:comment "nat -> nat")
|
||||
(define (f x)
|
||||
(printf "~s\n" x)
|
||||
|
@ -635,28 +635,28 @@ Here are two uses:
|
|||
(n-step g '(1 1))
|
||||
]
|
||||
|
||||
A contract for @scheme[n-step] must specify two aspects of
|
||||
@scheme[proc]'s behavior: its arity must include the number of elements
|
||||
in @scheme[inits], and it must return either a number or
|
||||
@scheme[#f]. The latter is easy, the former is difficult. At first
|
||||
A contract for @racket[n-step] must specify two aspects of
|
||||
@racket[proc]'s behavior: its arity must include the number of elements
|
||||
in @racket[inits], and it must return either a number or
|
||||
@racket[#f]. The latter is easy, the former is difficult. At first
|
||||
glance, this appears to suggest a contract that assigns a
|
||||
@italic{variable-arity} to @scheme[proc]:
|
||||
@schemeblock[
|
||||
@italic{variable-arity} to @racket[proc]:
|
||||
@racketblock[
|
||||
(->* ()
|
||||
(listof any/c)
|
||||
(or/c number? false/c))
|
||||
]
|
||||
This contract, however, says that the function must accept @emph{any}
|
||||
number of arguments, not a @emph{specific} but
|
||||
@emph{undetermined} number. Thus, applying @scheme[n-step] to
|
||||
@scheme[(lambda (x) x)] and @scheme[(list 1)] breaks the contract
|
||||
@emph{undetermined} number. Thus, applying @racket[n-step] to
|
||||
@racket[(lambda (x) x)] and @racket[(list 1)] breaks the contract
|
||||
because the given function accepts only one argument.
|
||||
|
||||
The correct contract uses the @scheme[unconstrained-domain->]
|
||||
The correct contract uses the @racket[unconstrained-domain->]
|
||||
combinator, which specifies only the range of a function, not its
|
||||
domain. It is then possible to combine this contract with an arity test to
|
||||
specify the correct @scheme[n-step]'s contract:
|
||||
@schemeblock[
|
||||
specify the correct @racket[n-step]'s contract:
|
||||
@racketblock[
|
||||
(provide/contract
|
||||
[n-step
|
||||
(->d ([proc
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
@title[#:tag "datatypes" #:style 'toc]{Built-In Datatypes}
|
||||
|
||||
The @seclink["to-scheme"]{previous chapter} introduced some of
|
||||
Scheme's built-in datatypes: numbers, booleans, strings, lists, and
|
||||
Racket's built-in datatypes: numbers, booleans, strings, lists, and
|
||||
procedures. This section provides a more complete coverage of the
|
||||
built-in datatypes for simple forms of data.
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
@(require scribble/manual
|
||||
scribble/eval
|
||||
scribble/bnf
|
||||
"guide-utils.ss")
|
||||
"guide-utils.ss"
|
||||
(for-label racket/serialize))
|
||||
|
||||
@(define posn-eval (make-base-eval))
|
||||
|
||||
|
@ -10,55 +11,46 @@
|
|||
|
||||
@refalso["structures"]{structure types}
|
||||
|
||||
New datatypes are normally created with the @scheme[define-struct]
|
||||
New datatypes are normally created with the @scheme[struct]
|
||||
form, which is the topic of this chapter. The class-based object
|
||||
system, which we defer to @secref["classes"], offers an alternate
|
||||
mechanism for creating new datatypes, but even classes and objects are
|
||||
implemented in terms of structure types.
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@section{Simple Structure Types: @scheme[define-struct]}
|
||||
@section{Simple Structure Types: @scheme[struct]}
|
||||
|
||||
@refalso["define-struct"]{@scheme[define-struct]}
|
||||
@refalso["define-struct"]{@scheme[struct]}
|
||||
|
||||
To a first approximation, the syntax of @scheme[define-struct] is
|
||||
To a first approximation, the syntax of @scheme[struct] is
|
||||
|
||||
@specform[
|
||||
(define-struct struct-id (field-id ...))
|
||||
(struct struct-id (field-id ...))
|
||||
]{}
|
||||
|
||||
A @scheme[define-struct] declaration binds @scheme[_struct-id], but
|
||||
only to static information about the structure type that cannot be
|
||||
used directly:
|
||||
|
||||
@def+int[
|
||||
@as-examples[@schemeblock+eval[
|
||||
#:eval posn-eval
|
||||
(define-struct posn (x y))
|
||||
posn
|
||||
]
|
||||
(struct posn (x y))
|
||||
]]
|
||||
|
||||
We show two uses of the @scheme[_struct-id] binding below in
|
||||
@secref["struct-copy"] and @secref["struct-subtypes"].
|
||||
|
||||
Meanwhile, in addition to defining @scheme[_struct-id],
|
||||
@scheme[define-struct] also defines a number of identifiers that are
|
||||
built from @scheme[_struct-id] and the @scheme[_field-id]s:
|
||||
The @scheme[struct] form binds @scheme[_struct-id] and a number of
|
||||
identifiers that are built from @scheme[_struct-id] and the
|
||||
@scheme[_field-id]s:
|
||||
|
||||
@itemize[
|
||||
|
||||
@item{@schemeidfont{make-}@scheme[_struct-id] : a
|
||||
@deftech{constructor} function that takes as many arguments as
|
||||
the number of @scheme[_field-id]s, and returns an instance of
|
||||
the structure type.
|
||||
@item{@scheme[_struct-id] : a @deftech{constructor} function that
|
||||
takes as many arguments as the number of @scheme[_field-id]s,
|
||||
and returns an instance of the structure type.
|
||||
|
||||
@examples[#:eval posn-eval (make-posn 1 2)]}
|
||||
@examples[#:eval posn-eval (posn 1 2)]}
|
||||
|
||||
@item{@scheme[_struct-id]@schemeidfont{?} : a @deftech{predicate}
|
||||
function that takes a single argument and returns @scheme[#t]
|
||||
if it is an instance of the structure type, @scheme[#f]
|
||||
otherwise.
|
||||
|
||||
@examples[#:eval posn-eval (posn? 3) (posn? (make-posn 1 2))]}
|
||||
@examples[#:eval posn-eval (posn? 3) (posn? (posn 1 2))]}
|
||||
|
||||
@item{@scheme[_struct-id]@schemeidfont{-}@scheme[_field-id] : for
|
||||
each @scheme[_field-id], an @deftech{accessor} that extracts
|
||||
|
@ -66,7 +58,7 @@ built from @scheme[_struct-id] and the @scheme[_field-id]s:
|
|||
structure type.
|
||||
|
||||
@examples[#:eval posn-eval
|
||||
(posn-x (make-posn 1 2)) (posn-y (make-posn 1 2))]}
|
||||
(posn-x (posn 1 2)) (posn-y (posn 1 2))]}
|
||||
|
||||
@item{@schemeidfont{struct:}@scheme[_struct-id] : a
|
||||
@deftech{structure type descriptor}, which is a value that
|
||||
|
@ -76,9 +68,9 @@ built from @scheme[_struct-id] and the @scheme[_field-id]s:
|
|||
|
||||
]
|
||||
|
||||
A @scheme[define-struct] form places no constraints on the kinds of
|
||||
A @scheme[struct] form places no constraints on the kinds of
|
||||
values that can appear for fields in an instance of the structure
|
||||
type. For example, @scheme[(make-posn "apple" #f)] produces an
|
||||
type. For example, @scheme[(posn "apple" #f)] produces an
|
||||
instance of @scheme[posn], even though @scheme["apple"] and
|
||||
@scheme[#f] are not valid coordinates for the obvious uses of
|
||||
@scheme[posn] instances. Enforcing constraints on field values, such
|
||||
|
@ -99,7 +91,7 @@ modified.
|
|||
]
|
||||
|
||||
The @scheme[_struct-id] that appears after @scheme[struct-copy] must
|
||||
be a structure type name bound by @scheme[define-struct] (i.e., the
|
||||
be a structure type name bound by @scheme[struct] (i.e., the
|
||||
name that cannot be used directly as an expression). The
|
||||
@scheme[_struct-expr] must produce an instance of the structure type.
|
||||
The result is a new instance of the structure tpe that is like the old
|
||||
|
@ -108,7 +100,7 @@ the value of the corresponding @scheme[_expr].
|
|||
|
||||
@examples[
|
||||
#:eval posn-eval
|
||||
(define p1 (make-posn 1 2))
|
||||
(define p1 (posn 1 2))
|
||||
(define p2 (struct-copy posn p1 [x 3]))
|
||||
(list (posn-x p2) (posn-y p2))
|
||||
(list (posn-x p1) (posn-x p2))
|
||||
|
@ -118,22 +110,22 @@ the value of the corresponding @scheme[_expr].
|
|||
@; ------------------------------------------------------------
|
||||
@section[#:tag "struct-subtypes"]{Structure Subtypes}
|
||||
|
||||
An extended form of @scheme[define-struct] can be used to define a
|
||||
An extended form of @scheme[struct] can be used to define a
|
||||
@defterm{structure subtype}, which is a structure type that extends an
|
||||
existing structure type:
|
||||
|
||||
@specform[
|
||||
(define-struct (struct-id super-id) (field-id ...))
|
||||
(struct struct-id super-id (field-id ...))
|
||||
]
|
||||
|
||||
The @scheme[_super-id] must be a structure type name bound by
|
||||
@scheme[define-struct] (i.e., the name that cannot be used directly as
|
||||
@scheme[struct] (i.e., the name that cannot be used directly as
|
||||
an expression).
|
||||
|
||||
@as-examples[@schemeblock+eval[
|
||||
#:eval posn-eval
|
||||
(define-struct posn (x y))
|
||||
(define-struct (3d-posn posn) (z))
|
||||
(struct posn (x y))
|
||||
(struct 3d-posn posn (z))
|
||||
]]
|
||||
|
||||
A structure subtype inherits the fields of its supertype, and the
|
||||
|
@ -144,7 +136,7 @@ supertype.
|
|||
|
||||
@examples[
|
||||
#:eval posn-eval
|
||||
(define p (make-3d-posn 1 2 3))
|
||||
(define p (3d-posn 1 2 3))
|
||||
p
|
||||
(posn? p)
|
||||
(posn-x p)
|
||||
|
@ -157,7 +149,7 @@ p
|
|||
With a structure type definition like
|
||||
|
||||
@schemeblock[
|
||||
(define-struct posn (x y))
|
||||
(struct posn (x y))
|
||||
]
|
||||
|
||||
an instance of the structure type prints in a way that does not show
|
||||
|
@ -171,14 +163,14 @@ To make a structure type @deftech{transparent}, use the
|
|||
|
||||
@def+int[
|
||||
#:eval posn-eval
|
||||
(define-struct posn (x y)
|
||||
#:transparent)
|
||||
(make-posn 1 2)
|
||||
(struct posn (x y)
|
||||
#:transparent)
|
||||
(posn 1 2)
|
||||
]
|
||||
|
||||
An instance of a transparent structure type prints like a vector, and
|
||||
it shows the content of the structure's fields. A transparent
|
||||
structure type also allows reflective operations, such as
|
||||
An instance of a transparent structure type prints like a call to the
|
||||
constructor, so that it shows the structures field values. A
|
||||
transparent structure type also allows reflective operations, such as
|
||||
@scheme[struct?] and @scheme[struct-info], to be used on its instances
|
||||
(see @secref["reflection"]).
|
||||
|
||||
|
@ -197,15 +189,15 @@ to mere instance identity for opaque structure types:
|
|||
|
||||
@def+int[
|
||||
#:eval posn-eval
|
||||
(define-struct glass (width height) #:transparent)
|
||||
(equal? (make-glass 1 2) (make-glass 1 2))
|
||||
(struct glass (width height) #:transparent)
|
||||
(equal? (glass 1 2) (glass 1 2))
|
||||
]
|
||||
@def+int[
|
||||
#:eval posn-eval
|
||||
(define-struct lead (width height))
|
||||
(define slab (make-lead 1 2))
|
||||
(struct lead (width height))
|
||||
(define slab (lead 1 2))
|
||||
(equal? slab slab)
|
||||
(equal? slab (make-lead 1 2))
|
||||
(equal? slab (lead 1 2))
|
||||
]
|
||||
|
||||
To support instances comparisons via @scheme[equal?] without making
|
||||
|
@ -214,7 +206,7 @@ keyword, @scheme[prop:equal+hash], and then a list of three functions:
|
|||
|
||||
@def+int[
|
||||
#:eval posn-eval
|
||||
(define-struct lead (width height)
|
||||
(struct lead (width height)
|
||||
#:property
|
||||
prop:equal+hash
|
||||
(list (lambda (a b equal?-recur)
|
||||
|
@ -229,7 +221,7 @@ keyword, @scheme[prop:equal+hash], and then a list of three functions:
|
|||
(code:comment @#,t{compute secondary hash code of @scheme[a]})
|
||||
(+ (hash2-recur (lead-width a))
|
||||
(hash2-recur (lead-height a))))))
|
||||
(equal? (make-lead 1 2) (make-lead 1 2))
|
||||
(equal? (lead 1 2) (lead 1 2))
|
||||
]
|
||||
|
||||
The first function in the list implements the @scheme[equal?] test on
|
||||
|
@ -241,9 +233,9 @@ secondary hash codes for use with @tech{hash tables}:
|
|||
@interaction[
|
||||
#:eval posn-eval
|
||||
(define h (make-hash))
|
||||
(hash-set! h (make-lead 1 2) 3)
|
||||
(hash-ref h (make-lead 1 2))
|
||||
(hash-ref h (make-lead 2 1))
|
||||
(hash-set! h (lead 1 2) 3)
|
||||
(hash-ref h (lead 1 2))
|
||||
(hash-ref h (lead 2 1))
|
||||
]
|
||||
|
||||
The first function provided with @scheme[prop:equal+hash] is not
|
||||
|
@ -257,33 +249,33 @@ types that are supposed to be equivalent.
|
|||
@; ------------------------------------------------------------
|
||||
@section{Structure Type Generativity}
|
||||
|
||||
Each time that a @scheme[define-struct] form is evaluated, it
|
||||
Each time that a @scheme[struct] form is evaluated, it
|
||||
generates a structure type that is distinct from all existing
|
||||
structure types, even if some other structure type has the same name
|
||||
and fields.
|
||||
|
||||
This generativity is useful for enforcing abstractions and
|
||||
implementing programs such as interpreters, but beware of placing a
|
||||
@scheme[define-struct] form in positions that are evaluated multiple
|
||||
@scheme[struct] form in positions that are evaluated multiple
|
||||
times.
|
||||
|
||||
@defexamples[
|
||||
(define (add-bigger-fish lst)
|
||||
(define-struct fish (size) #:transparent) (code:comment #,(t "new every time"))
|
||||
(struct fish (size) #:transparent) (code:comment #,(t "new every time"))
|
||||
(cond
|
||||
[(null? lst) (list (make-fish 1))]
|
||||
[else (cons (make-fish (* 2 (fish-size (car lst))))
|
||||
[(null? lst) (list (fish 1))]
|
||||
[else (cons (fish (* 2 (fish-size (car lst))))
|
||||
lst)]))
|
||||
|
||||
(add-bigger-fish null)
|
||||
(add-bigger-fish (add-bigger-fish null))
|
||||
]
|
||||
@defs+int[
|
||||
[(define-struct fish (size) #:transparent)
|
||||
[(struct fish (size) #:transparent)
|
||||
(define (add-bigger-fish lst)
|
||||
(cond
|
||||
[(null? lst) (list (make-fish 1))]
|
||||
[else (cons (make-fish (* 2 (fish-size (car lst))))
|
||||
[(null? lst) (list (fish 1))]
|
||||
[else (cons (fish (* 2 (fish-size (car lst))))
|
||||
lst)]))]
|
||||
(add-bigger-fish (add-bigger-fish null))
|
||||
]
|
||||
|
@ -322,16 +314,16 @@ the quotes above are optional:
|
|||
]
|
||||
|
||||
When you use the @scheme[#:prefab] keyword with
|
||||
@scheme[define-struct], instead of generating a new structure type,
|
||||
@scheme[struct], instead of generating a new structure type,
|
||||
you obtain bindings that work with the existing prefab structure type:
|
||||
|
||||
@interaction[
|
||||
#:eval posn-eval
|
||||
(define lunch '#s(sprout bean))
|
||||
(define-struct sprout (kind) #:prefab)
|
||||
(struct sprout (kind) #:prefab)
|
||||
(sprout? lunch)
|
||||
(sprout-kind lunch)
|
||||
(make-sprout 'garlic)
|
||||
(sprout 'garlic)
|
||||
]
|
||||
|
||||
The field name @schemeidfont{kind} above does not matter for finding
|
||||
|
@ -343,7 +335,7 @@ than the one with a single field:
|
|||
@interaction[
|
||||
#:eval posn-eval
|
||||
(sprout? #s(sprout bean #f 17))
|
||||
(code:line (define-struct sprout (kind yummy? count) #:prefab) (code:comment @#,t{redefine}))
|
||||
(code:line (struct sprout (kind yummy? count) #:prefab) (code:comment @#,t{redefine}))
|
||||
(sprout? #s(sprout bean #f 17))
|
||||
(sprout? lunch)
|
||||
]
|
||||
|
@ -355,10 +347,10 @@ prefab structure types, and the printed form of the structure type's
|
|||
name encodes all of the relevant details.
|
||||
|
||||
@interaction[
|
||||
(define-struct building (rooms [location #:mutable]) #:prefab)
|
||||
(define-struct (house building) ([occupied #:auto]) #:prefab
|
||||
(struct building (rooms [location #:mutable]) #:prefab)
|
||||
(struct house building ([occupied #:auto]) #:prefab
|
||||
#:auto-value 'no)
|
||||
(make-house 5 'factory)
|
||||
(house 5 'factory)
|
||||
]
|
||||
|
||||
Every @tech{prefab} structure type is @tech{transparent}---but even
|
||||
|
@ -406,13 +398,13 @@ be serialized, however, if they are defined with
|
|||
@; ------------------------------------------------------------
|
||||
@section[#:tag "struct-options"]{More Structure Type Options}
|
||||
|
||||
The full syntax of @scheme[define-struct] supports many options, both
|
||||
The full syntax of @scheme[struct] supports many options, both
|
||||
at the structure-type level and at the level of individual fields:
|
||||
|
||||
@specform/subs[(define-struct id-maybe-super (field ...)
|
||||
struct-option ...)
|
||||
([id-maybe-super struct-id
|
||||
(struct-id super-id)]
|
||||
@specform/subs[(struct struct-id maybe-super (field ...)
|
||||
struct-option ...)
|
||||
([maybe-super code:blank
|
||||
super-id]
|
||||
[field field-id
|
||||
[field-id field-option ...]])]
|
||||
|
||||
|
@ -426,8 +418,8 @@ A @scheme[_struct-option] always starts with a keyword:
|
|||
that sets the value of the corresponding field in an instance of
|
||||
the structure type.
|
||||
|
||||
@defexamples[(define-struct dot (x y) #:mutable)
|
||||
(define d (make-dot 1 2))
|
||||
@defexamples[(struct dot (x y) #:mutable)
|
||||
(define d (dot 1 2))
|
||||
(dot-x d)
|
||||
(set-dot-x! d 10)
|
||||
(dot-x d)]
|
||||
|
@ -437,8 +429,8 @@ A @scheme[_struct-option] always starts with a keyword:
|
|||
mutable.
|
||||
|
||||
@defexamples[
|
||||
(define-struct person (name [age #:mutable]))
|
||||
(define friend (make-person "Barney" 5))
|
||||
(struct person (name [age #:mutable]))
|
||||
(define friend (person "Barney" 5))
|
||||
(set-person-age! friend 6)
|
||||
(set-person-name! friend "Mary")]}
|
||||
|
||||
|
@ -464,10 +456,10 @@ A @scheme[_struct-option] always starts with a keyword:
|
|||
functions are bound only if @scheme[#:mutator] is also specified.
|
||||
|
||||
@defexamples[
|
||||
(define-struct posn (x y [z #:auto])
|
||||
#:transparent
|
||||
#:auto-value 0)
|
||||
(make-posn 1 2)
|
||||
(struct posn (x y [z #:auto])
|
||||
#:transparent
|
||||
#:auto-value 0)
|
||||
(posn 1 2)
|
||||
]}
|
||||
|
||||
@;-- FIXME:
|
||||
|
@ -486,18 +478,18 @@ A @scheme[_struct-option] always starts with a keyword:
|
|||
|
||||
@defexamples[
|
||||
#:eval posn-eval
|
||||
(define-struct thing (name)
|
||||
#:transparent
|
||||
#:guard (lambda (name type-name)
|
||||
(cond
|
||||
[(string? name) name]
|
||||
[(symbol? name) (symbol->string name)]
|
||||
[else (error type-name
|
||||
"bad name: ~e"
|
||||
name)])))
|
||||
(make-thing "apple")
|
||||
(make-thing 'apple)
|
||||
(make-thing 1/2)
|
||||
(struct thing (name)
|
||||
#:transparent
|
||||
#:guard (lambda (name type-name)
|
||||
(cond
|
||||
[(string? name) name]
|
||||
[(symbol? name) (symbol->string name)]
|
||||
[else (error type-name
|
||||
"bad name: ~e"
|
||||
name)])))
|
||||
(thing "apple")
|
||||
(thing 'apple)
|
||||
(thing 1/2)
|
||||
]
|
||||
|
||||
The guard is called even when subtype instances are created. In that
|
||||
|
@ -507,15 +499,15 @@ A @scheme[_struct-option] always starts with a keyword:
|
|||
|
||||
@defexamples[
|
||||
#:eval posn-eval
|
||||
(define-struct (person thing) (age)
|
||||
#:transparent
|
||||
#:guard (lambda (name age type-name)
|
||||
(if (negative? age)
|
||||
(error type-name "bad age: ~e" age)
|
||||
(values name age))))
|
||||
(make-person "John" 10)
|
||||
(make-person "Mary" -1)
|
||||
(make-person 10 10)]}
|
||||
(struct person thing (age)
|
||||
#:transparent
|
||||
#:guard (lambda (name age type-name)
|
||||
(if (negative? age)
|
||||
(error type-name "bad age: ~e" age)
|
||||
(values name age))))
|
||||
(person "John" 10)
|
||||
(person "Mary" -1)
|
||||
(person 10 10)]}
|
||||
|
||||
@specspecsubform[(code:line #:property prop-expr val-expr)]{
|
||||
Associates a @deftech{property} and value with the structure type.
|
||||
|
@ -525,13 +517,13 @@ A @scheme[_struct-option] always starts with a keyword:
|
|||
function.
|
||||
|
||||
@defexamples[
|
||||
(define-struct greeter (name)
|
||||
#:property prop:procedure
|
||||
(lambda (self other)
|
||||
(string-append
|
||||
"Hi " other
|
||||
", I'm " (greeter-name self))))
|
||||
(define joe-greet (make-greeter "Joe"))
|
||||
(struct greeter (name)
|
||||
#:property prop:procedure
|
||||
(lambda (self other)
|
||||
(string-append
|
||||
"Hi " other
|
||||
", I'm " (greeter-name self))))
|
||||
(define joe-greet (greeter "Joe"))
|
||||
(greeter-name joe-greet)
|
||||
(joe-greet "Mary")
|
||||
(joe-greet "John")]}
|
||||
|
@ -547,16 +539,16 @@ A @scheme[_struct-option] always starts with a keyword:
|
|||
|
||||
@defexamples[
|
||||
#:eval posn-eval
|
||||
(define (make-raven-constructor super-type)
|
||||
(define-struct raven ()
|
||||
#:super super-type
|
||||
#:transparent
|
||||
#:property prop:procedure (lambda (self)
|
||||
'nevermore))
|
||||
make-raven)
|
||||
(let ([r ((make-raven-constructor struct:posn) 1 2)])
|
||||
(define (raven-constructor super-type)
|
||||
(struct raven ()
|
||||
#:super super-type
|
||||
#:transparent
|
||||
#:property prop:procedure (lambda (self)
|
||||
'nevermore))
|
||||
raven)
|
||||
(let ([r ((raven-constructor struct:posn) 1 2)])
|
||||
(list r (r)))
|
||||
(let ([r ((make-raven-constructor struct:thing) "apple")])
|
||||
(let ([r ((raven-constructor struct:thing) "apple")])
|
||||
(list r (r)))]}
|
||||
|
||||
@; ----------------------------------------
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
|
||||
@(define def-eval (make-base-eval))
|
||||
|
||||
@title[#:tag "define"]{Definitions: @scheme[define]}
|
||||
@title[#:tag "define"]{Definitions: @racket[define]}
|
||||
|
||||
A basic definition has the form
|
||||
|
||||
@specform[(define id expr)]{}
|
||||
|
||||
in which case @scheme[_id] is bound to the result of
|
||||
@scheme[_expr].
|
||||
in which case @racket[_id] is bound to the result of
|
||||
@racket[_expr].
|
||||
|
||||
@defexamples[
|
||||
#:eval def-eval
|
||||
|
@ -23,14 +23,14 @@ salutation
|
|||
@;------------------------------------------------------------------------
|
||||
@section{Function Shorthand}
|
||||
|
||||
The @scheme[define] form also supports a shorthand for function
|
||||
The @racket[define] form also supports a shorthand for function
|
||||
definitions:
|
||||
|
||||
@specform[(define (id arg ...) body ...+)]{}
|
||||
|
||||
which is a shorthand for
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define _id (lambda (_arg ...) _body ...+))
|
||||
]
|
||||
|
||||
|
@ -50,7 +50,7 @@ which is a shorthand for
|
|||
(greet "John" "Doe")
|
||||
]
|
||||
|
||||
The function shorthand via @scheme[define] also supports a ``rest''
|
||||
The function shorthand via @racket[define] also supports a ``rest''
|
||||
argument (i.e., a final argument to collect extra arguments in a
|
||||
list):
|
||||
|
||||
|
@ -58,7 +58,7 @@ list):
|
|||
|
||||
which is a shorthand
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define _id (lambda (_arg ... . _rest-id) _body ...+))
|
||||
]
|
||||
|
||||
|
@ -72,7 +72,7 @@ which is a shorthand
|
|||
@;------------------------------------------------------------------------
|
||||
@section{Curried Function Shorthand}
|
||||
|
||||
Consider the following @scheme[make-add-suffix] function that takes a
|
||||
Consider the following @racket[make-add-suffix] function that takes a
|
||||
string and returns another function that takes a string:
|
||||
|
||||
@def+int[
|
||||
|
@ -82,7 +82,7 @@ string and returns another function that takes a string:
|
|||
(lambda (s) (string-append s s2))))
|
||||
]
|
||||
|
||||
Although it's not common, result of @scheme[make-add-suffix] could be
|
||||
Although it's not common, result of @racket[make-add-suffix] could be
|
||||
called directly, like this:
|
||||
|
||||
@interaction[
|
||||
|
@ -90,21 +90,21 @@ called directly, like this:
|
|||
((make-add-suffix "!") "hello")
|
||||
]
|
||||
|
||||
In a sense, @scheme[make-add-suffix] is a function takes two
|
||||
In a sense, @racket[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
|
||||
Using the function-shorthand form of @racket[define],
|
||||
@racket[make-add-suffix] can be written equivalently as
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define (make-add-suffix s2)
|
||||
(lambda (s) (string-append s s2)))
|
||||
]
|
||||
|
||||
This shorthand reflects the shape of the function call
|
||||
@scheme[(make-add-suffix "!")]. The @scheme[define] form further
|
||||
@racket[(make-add-suffix "!")]. The @racket[define] form further
|
||||
supports a shorthand for defining curried functions that reflects
|
||||
nested function calls:
|
||||
|
||||
|
@ -122,26 +122,26 @@ nested function calls:
|
|||
(louder "really")
|
||||
]
|
||||
|
||||
The full syntax of the function shorthand for @scheme[define] is as follows:
|
||||
The full syntax of the function shorthand for @racket[define] is as follows:
|
||||
|
||||
@specform/subs[(define (head args) body ...+)
|
||||
([head id
|
||||
(head args)]
|
||||
[args (code:line arg ...)
|
||||
(code:line arg ... @#,schemeparenfont{.} rest-id)])]{}
|
||||
(code:line arg ... @#,racketparenfont{.} rest-id)])]{}
|
||||
|
||||
The expansion of this shorthand has one nested @scheme[lambda] form
|
||||
for each @scheme[_head] in the definition, where the innermost
|
||||
@scheme[_head] corresponds to the outermost @scheme[lambda].
|
||||
The expansion of this shorthand has one nested @racket[lambda] form
|
||||
for each @racket[_head] in the definition, where the innermost
|
||||
@racket[_head] corresponds to the outermost @racket[lambda].
|
||||
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "multiple-values"]{Multiple Values and @scheme[define-values]}
|
||||
@section[#:tag "multiple-values"]{Multiple Values and @racket[define-values]}
|
||||
|
||||
A Scheme expression normally produces a single result, but some
|
||||
A Racket expression normally produces a single result, but some
|
||||
expressions can produce multiple results. For example,
|
||||
@scheme[quotient] and @scheme[remainder] each produce a single value,
|
||||
but @scheme[quotient/remainder] produces the same two values at once:
|
||||
@racket[quotient] and @racket[remainder] each produce a single value,
|
||||
but @racket[quotient/remainder] produces the same two values at once:
|
||||
|
||||
@interaction[
|
||||
#:eval def-eval
|
||||
|
@ -154,7 +154,7 @@ As shown above, the @tech{REPL} prints each result value on its own
|
|||
line.
|
||||
|
||||
Multiple-valued functions can be implemented in terms of the
|
||||
@scheme[values] function, which takes any number of values and
|
||||
@racket[values] function, which takes any number of values and
|
||||
returns them as the results:
|
||||
|
||||
@interaction[
|
||||
|
@ -171,13 +171,13 @@ returns them as the results:
|
|||
(split-name "Adam Smith")
|
||||
]
|
||||
|
||||
The @scheme[define-values] form binds multiple identifiers at once to
|
||||
The @racket[define-values] form binds multiple identifiers at once to
|
||||
multiple results produced from a single expression:
|
||||
|
||||
@specform[(define-values (id ...) expr)]{}
|
||||
|
||||
The number of results produced by the @scheme[_expr] must match the
|
||||
number of @scheme[_id]s.
|
||||
The number of results produced by the @racket[_expr] must match the
|
||||
number of @racket[_id]s.
|
||||
|
||||
@defexamples[
|
||||
#:eval def-eval
|
||||
|
@ -186,23 +186,23 @@ given
|
|||
surname
|
||||
]
|
||||
|
||||
A @scheme[define] form (that is not a function shorthand) is
|
||||
equivalent to a @scheme[define-values] form with a single @scheme[_id].
|
||||
A @racket[define] form (that is not a function shorthand) is
|
||||
equivalent to a @racket[define-values] form with a single @racket[_id].
|
||||
|
||||
@refdetails["define"]{definitions}
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "intdefs"]{Internal Definitions}
|
||||
|
||||
When the grammar for a syntactic form specifies @scheme[_body], then
|
||||
When the grammar for a syntactic form specifies @racket[_body], then
|
||||
the corresponding form can be either a definition or an expression.
|
||||
A definition as a @scheme[_body] is an @defterm{internal definition}.
|
||||
A definition as a @racket[_body] is an @defterm{internal definition}.
|
||||
|
||||
All internal definitions in a @scheme[_body] sequence must appear
|
||||
before any expression, and the last @scheme[_body] must be an
|
||||
All internal definitions in a @racket[_body] sequence must appear
|
||||
before any expression, and the last @racket[_body] must be an
|
||||
expression.
|
||||
|
||||
For example, the syntax of @scheme[lambda] is
|
||||
For example, the syntax of @racket[lambda] is
|
||||
|
||||
@specform[
|
||||
(lambda gen-formals
|
||||
|
@ -211,7 +211,7 @@ For example, the syntax of @scheme[lambda] is
|
|||
|
||||
so the following are valid instances of the grammar:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(lambda (f) (code:comment @#,elem{no definitions})
|
||||
(printf "running\n")
|
||||
(f 0))
|
||||
|
@ -236,7 +236,7 @@ so the following are valid instances of the grammar:
|
|||
(call f n))
|
||||
]
|
||||
|
||||
Internal definitions in a particular @scheme[_body] sequence are
|
||||
Internal definitions in a particular @racket[_body] sequence are
|
||||
mutually recursive; that is, any definition can refer to any other
|
||||
definition---as long as the reference isn't actually evaluated before
|
||||
its definition takes place. If a definition is referenced too early,
|
||||
|
@ -249,11 +249,11 @@ the result is a special value @|undefined-const|.
|
|||
(weird)
|
||||
]
|
||||
|
||||
A sequence of internal definitions using just @scheme[define] is
|
||||
easily translated to an equivalent @scheme[letrec] form (as introduced
|
||||
A sequence of internal definitions using just @racket[define] is
|
||||
easily translated to an equivalent @racket[letrec] form (as introduced
|
||||
in the next section). However, other definition forms can appear as a
|
||||
@scheme[_body], including @scheme[define-values], @scheme[define-struct] (see
|
||||
@secref["define-struct"]) or @scheme[define-syntax] (see
|
||||
@racket[_body], including @racket[define-values], @racket[struct] (see
|
||||
@secref["define-struct"]) or @racket[define-syntax] (see
|
||||
@secref["macros"]).
|
||||
|
||||
@refdetails/gory["intdef-body"]{internal definitions}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
@title[#:tag "scheme-forms" #:style 'toc]{Expressions and Definitions}
|
||||
|
||||
The @secref["to-scheme"] chapter introduced some of Scheme's syntactic
|
||||
The @secref["to-scheme"] chapter introduced some of Racket's syntactic
|
||||
forms: definitions, procedure applications, conditionals, and so
|
||||
on. This section provides more details on those forms, plus a few
|
||||
additional basic forms.
|
||||
|
@ -17,32 +17,32 @@ additional basic forms.
|
|||
This chapter (and the rest of the documentation) uses a slightly
|
||||
different notation than the character-based grammars of the
|
||||
@secref["to-scheme"] chapter. The grammar for a use of a syntactic
|
||||
form @schemekeywordfont{something} is shown like this:
|
||||
form @racketkeywordfont{something} is shown like this:
|
||||
|
||||
@specform[(#,(schemekeywordfont "something") [id ...+] an-expr ...)]
|
||||
@specform[(#,(racketkeywordfont "something") [id ...+] an-expr ...)]
|
||||
|
||||
The italicized meta-variables in this specification, such as
|
||||
@scheme[_id] and @scheme[_an-expr], use the syntax of Scheme
|
||||
identifiers, so @scheme[_an-expr] is one meta-variable. A naming
|
||||
@racket[_id] and @racket[_an-expr], use the syntax of Racket
|
||||
identifiers, so @racket[_an-expr] is one meta-variable. A naming
|
||||
convention implicitly defines the meaning of many meta-variables:
|
||||
|
||||
@itemize[
|
||||
|
||||
@item{A meta-variable that ends in @scheme[_id] stands for an
|
||||
identifier, such as @schemeidfont{x} or
|
||||
@schemeidfont{my-favorite-martian}.}
|
||||
@item{A meta-variable that ends in @racket[_id] stands for an
|
||||
identifier, such as @racketidfont{x} or
|
||||
@racketidfont{my-favorite-martian}.}
|
||||
|
||||
@item{A meta-identifier that ends in @scheme[_keyword] stands
|
||||
for a keyword, such as @scheme[#:tag].}
|
||||
@item{A meta-identifier that ends in @racket[_keyword] stands
|
||||
for a keyword, such as @racket[#:tag].}
|
||||
|
||||
@item{A meta-identifier that ends with @scheme[_expr] stands for any
|
||||
@item{A meta-identifier that ends with @racket[_expr] stands for any
|
||||
sub-form, and it will be parsed as an expression.}
|
||||
|
||||
@item{A meta-identifier that ends with @scheme[_body] stands for any
|
||||
@item{A meta-identifier that ends with @racket[_body] stands for any
|
||||
sub-form; it will be parsed as either a local definition or an
|
||||
expression. A @scheme[_body] can parse as a definition only if
|
||||
expression. A @racket[_body] can parse as a definition only if
|
||||
it is not preceded by any expression, and the last
|
||||
@scheme[_body] must be an expression; see also @secref["intdefs"].}
|
||||
@racket[_body] must be an expression; see also @secref["intdefs"].}
|
||||
|
||||
]
|
||||
|
||||
|
@ -51,18 +51,18 @@ forms, where square brackets are normally used (by convention). That
|
|||
is, square brackets @italic{do not} mean optional parts of the
|
||||
syntactic form.
|
||||
|
||||
A @schememetafont{...} indicates zero or more repetitions of the
|
||||
preceding form, and @schememetafont{...+} indicates one or more
|
||||
A @racketmetafont{...} indicates zero or more repetitions of the
|
||||
preceding form, and @racketmetafont{...+} indicates one or more
|
||||
repetitions of the preceding datum. Otherwise, non-italicized
|
||||
identifiers stand for themselves.
|
||||
|
||||
Based on the above grammar, then, here are a few conforming uses of
|
||||
@schemekeywordfont{something}:
|
||||
@racketkeywordfont{something}:
|
||||
|
||||
@schemeblock[
|
||||
(#,(schemekeywordfont "something") [x])
|
||||
(#,(schemekeywordfont "something") [x] (+ 1 2))
|
||||
(#,(schemekeywordfont "something") [x my-favorite-martian x] (+ 1 2) #f)
|
||||
@racketblock[
|
||||
(#,(racketkeywordfont "something") [x])
|
||||
(#,(racketkeywordfont "something") [x] (+ 1 2))
|
||||
(#,(racketkeywordfont "something") [x my-favorite-martian x] (+ 1 2) #f)
|
||||
]
|
||||
|
||||
Some syntactic-form specifications refer to meta-variables that are
|
||||
|
@ -70,12 +70,12 @@ 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 ...)
|
||||
@specform/subs[(#,(racketkeywordfont "something-else") [thing ...+] an-expr ...)
|
||||
([thing thing-id
|
||||
thing-keyword])]
|
||||
|
||||
The above example says that, within a @schemekeywordfont{something-else}
|
||||
form, a @scheme[_thing] is either an identifier or a keyword.
|
||||
The above example says that, within a @racketkeywordfont{something-else}
|
||||
form, a @racket[_thing] is either an identifier or a keyword.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
(module guide-utils scheme/base
|
||||
(module guide-utils racket/base
|
||||
(require scribble/manual
|
||||
scribble/struct
|
||||
scribble/decode
|
||||
scribble/eval
|
||||
"../icons.ss")
|
||||
|
||||
(require (for-label scheme/base))
|
||||
(provide (for-label (all-from-out scheme/base)))
|
||||
(require (for-label racket/base))
|
||||
(provide (for-label (all-from-out racket/base)))
|
||||
|
||||
(provide Quick MzScheme HtDP
|
||||
tool
|
||||
|
|
|
@ -2,19 +2,18 @@
|
|||
@(require scribble/eval
|
||||
"guide-utils.ss")
|
||||
|
||||
@title{@bold{Guide}: PLT Scheme}
|
||||
@title{@bold{Guide}: Racket}
|
||||
|
||||
@author["Matthew Flatt" "Robert Bruce Findler" "PLT"]
|
||||
|
||||
This guide is intended for programmers who are new to Scheme, new to PLT
|
||||
Scheme, or new to some part of PLT Scheme. It assumes
|
||||
programming experience, so if you are new to programming, consider
|
||||
instead reading @|HtDP|. If you want a brief introduction to PLT
|
||||
Scheme, start with @|Quick|.
|
||||
This guide is intended for programmers who are new to Racket or new to
|
||||
some part of Racket. It assumes programming experience, so if you are
|
||||
new to programming, consider instead reading @|HtDP|. If you want an
|
||||
especially quick introduction to Racket, start with @|Quick|.
|
||||
|
||||
@seclink["to-scheme"]{Chapter 2} provides a brief introduction to
|
||||
Scheme. From @seclink["datatypes"]{Chapter 3} on, this guide dives
|
||||
into details---covering much of the PLT Scheme toolbox, but leaving
|
||||
Racket. From @seclink["datatypes"]{Chapter 3} on, this guide dives
|
||||
into details---covering much of the Racket toolbox, but leaving
|
||||
precise details to @|MzScheme| and other reference manuals.
|
||||
|
||||
@table-of-contents[]
|
||||
|
|
|
@ -22,7 +22,7 @@ way that an identifier can be quoted to produce a symbol, a keyword
|
|||
can be quoted to produce a value. The same term ``keyword'' is used in
|
||||
both cases, but we sometimes use @defterm{keyword value} to refer more
|
||||
specifically to the result of a quote-keyword expression or of
|
||||
@scheme[string->keyword]. An unquoted keyword is not an expression,
|
||||
@racket[string->keyword]. An unquoted keyword is not an expression,
|
||||
just as an unquoted identifier does not produce a symbol:
|
||||
|
||||
@examples[
|
||||
|
@ -37,12 +37,12 @@ run-time flags and enumerations, use symbols instead of keywords. The
|
|||
example below illustrates the distinct roles of keywords and symbols.
|
||||
|
||||
@examples[
|
||||
(code:line (define dir (find-system-path 'temp-dir)) (code:comment @#,t{not @scheme['#:temp-dir]}))
|
||||
(code:line (define dir (find-system-path 'temp-dir)) (code:comment @#,t{not @racket['#:temp-dir]}))
|
||||
(with-output-to-file (build-path dir "stuff.txt")
|
||||
(lambda () (printf "example\n"))
|
||||
(code:comment @#,t{optional @scheme[#:mode] argument can be @scheme['text] or @scheme['binary]})
|
||||
(code:comment @#,t{optional @racket[#:mode] argument can be @racket['text] or @racket['binary]})
|
||||
#:mode 'text
|
||||
(code:comment @#,t{optional @scheme[#:exists] argument can be @scheme['replace], @scheme['truncate], ...})
|
||||
(code:comment @#,t{optional @racket[#:exists] argument can be @racket['replace], @racket['truncate], ...})
|
||||
#:exists 'replace)
|
||||
]
|
||||
|
||||
|
|
|
@ -5,17 +5,17 @@
|
|||
|
||||
@(define greet-eval (make-base-eval))
|
||||
|
||||
@title[#:tag "lambda"]{Functions@aux-elem{ (Procedures)}: @scheme[lambda]}
|
||||
@title[#:tag "lambda"]{Functions@aux-elem{ (Procedures)}: @racket[lambda]}
|
||||
|
||||
A @scheme[lambda] expression creates a function. In the simplest
|
||||
case, a @scheme[lambda] expression has the form
|
||||
A @racket[lambda] expression creates a function. In the simplest
|
||||
case, a @racket[lambda] expression has the form
|
||||
|
||||
@specform[
|
||||
(lambda (arg-id ...)
|
||||
body ...+)
|
||||
]
|
||||
|
||||
A @scheme[lambda] form with @math{n} @scheme[_arg-id]s accepts
|
||||
A @racket[lambda] form with @math{n} @racket[_arg-id]s accepts
|
||||
@math{n} arguments:
|
||||
|
||||
@interaction[
|
||||
|
@ -30,17 +30,17 @@ A @scheme[lambda] form with @math{n} @scheme[_arg-id]s accepts
|
|||
@;------------------------------------------------------------------------
|
||||
@section{Declaring a Rest Argument}
|
||||
|
||||
A @scheme[lambda] expression can also have the form
|
||||
A @racket[lambda] expression can also have the form
|
||||
|
||||
@specform[
|
||||
(lambda rest-id
|
||||
body ...+)
|
||||
]
|
||||
|
||||
That is, a @scheme[lambda] expression can have a single
|
||||
@scheme[_rest-id] that is not surrounded by parentheses. The resulting
|
||||
That is, a @racket[lambda] expression can have a single
|
||||
@racket[_rest-id] that is not surrounded by parentheses. The resulting
|
||||
function accepts any number of arguments, and the arguments are put
|
||||
into a list bound to @scheme[_rest-id].
|
||||
into a list bound to @racket[_rest-id].
|
||||
|
||||
@examples[
|
||||
((lambda x x)
|
||||
|
@ -50,10 +50,10 @@ into a list bound to @scheme[_rest-id].
|
|||
1 2 3)
|
||||
]
|
||||
|
||||
Functions with a @scheme[_rest-id] often use @scheme[apply] to call
|
||||
Functions with a @racket[_rest-id] often use @racket[apply] to call
|
||||
another function that accepts any number of arguments.
|
||||
|
||||
@guideother{@secref["apply"] describes @scheme[apply].}
|
||||
@guideother{@secref["apply"] describes @racket[apply].}
|
||||
|
||||
@defexamples[
|
||||
(define max-mag
|
||||
|
@ -64,8 +64,8 @@ another function that accepts any number of arguments.
|
|||
(max-mag 1 -2 0)
|
||||
]
|
||||
|
||||
The @scheme[lambda] form also supports required arguments combined
|
||||
with a @scheme[_rest-id]:
|
||||
The @racket[lambda] form also supports required arguments combined
|
||||
with a @racket[_rest-id]:
|
||||
|
||||
@specform[
|
||||
(lambda (arg-id ...+ . rest-id)
|
||||
|
@ -73,7 +73,7 @@ with a @scheme[_rest-id]:
|
|||
]
|
||||
|
||||
The result of this form is a function that requires at least as many
|
||||
arguments as @scheme[_arg-id]s, and also accepts any number of
|
||||
arguments as @racket[_arg-id]s, and also accepts any number of
|
||||
additional arguments.
|
||||
|
||||
@defexamples[
|
||||
|
@ -85,14 +85,14 @@ additional arguments.
|
|||
(max-mag)
|
||||
]
|
||||
|
||||
A @scheme[_rest-id] variable is sometimes called a @defterm{rest
|
||||
A @racket[_rest-id] variable is sometimes called a @defterm{rest
|
||||
argument}, because it accepts the ``rest'' of the function arguments.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Declaring Optional Arguments}
|
||||
|
||||
Instead of just an identifier, an argument (other than a rest
|
||||
argument) in a @scheme[lambda] form can be specified with an
|
||||
argument) in a @racket[lambda] form can be specified with an
|
||||
identifier and a default value:
|
||||
|
||||
@specform/subs[
|
||||
|
@ -105,11 +105,11 @@ identifier and a default value:
|
|||
[arg-id default-expr]])
|
||||
]{}
|
||||
|
||||
A argument of the form @scheme[[arg-id default-expr]] is
|
||||
A argument of the form @racket[[arg-id default-expr]] is
|
||||
optional. When the argument is not supplied in an application,
|
||||
@scheme[_default-expr] produces the default value. The
|
||||
@scheme[_default-expr] can refer to any preceding @scheme[_arg-id],
|
||||
and every following @scheme[_arg-id] must have a default as well.
|
||||
@racket[_default-expr] produces the default value. The
|
||||
@racket[_default-expr] can refer to any preceding @racket[_arg-id],
|
||||
and every following @racket[_arg-id] must have a default as well.
|
||||
|
||||
@defexamples[
|
||||
(define greet
|
||||
|
@ -133,7 +133,7 @@ and every following @scheme[_arg-id] must have a default as well.
|
|||
|
||||
@section[#:tag "lambda-keywords"]{Declaring Keyword Arguments}
|
||||
|
||||
A @scheme[lambda] form can declare an argument to be passed by
|
||||
A @racket[lambda] form can declare an argument to be passed by
|
||||
keyword, instead of position. Keyword arguments can be mixed with
|
||||
by-position arguments, and default-value expressions can be supplied
|
||||
for either kind of argument:
|
||||
|
@ -153,8 +153,8 @@ calls with keywords.}
|
|||
(code:line arg-keyword [arg-id default-expr])])
|
||||
]{}
|
||||
|
||||
An argument specified as @scheme[(code:line _arg-keyword _arg-id)] is
|
||||
supplied by an application using the same @scheme[_arg-keyword]. The
|
||||
An argument specified as @racket[(code:line _arg-keyword _arg-id)] is
|
||||
supplied by an application using the same @racket[_arg-keyword]. The
|
||||
position of the keyword--identifier pair in the argument list does not
|
||||
matter for matching with arguments in an application, because it will
|
||||
be matched to an argument value by keyword instead of by position.
|
||||
|
@ -168,7 +168,7 @@ be matched to an argument value by keyword instead of by position.
|
|||
(greet #:last "Doe" "John")
|
||||
]
|
||||
|
||||
An @scheme[(code:line _arg-keyword [_arg-id _default-expr])] argument
|
||||
An @racket[(code:line _arg-keyword [_arg-id _default-expr])] argument
|
||||
specifies a keyword-based argument with a default value.
|
||||
|
||||
@defexamples[
|
||||
|
@ -183,16 +183,16 @@ specifies a keyword-based argument with a default value.
|
|||
(greet "Karl" #:last "Marx" #:hi "Guten Tag")
|
||||
]
|
||||
|
||||
The @scheme[lambda] form does not directly support the creation
|
||||
The @racket[lambda] form does not directly support the creation
|
||||
of a function that accepts ``rest'' keywords. To construct a
|
||||
function that accepts all keyword arguments, use
|
||||
@scheme[make-keyword-procedure]. The function supplied to
|
||||
@scheme[make-keyword-procedure] receives keyword arguments
|
||||
@racket[make-keyword-procedure]. The function supplied to
|
||||
@racket[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.
|
||||
|
||||
@guideother{@secref["apply"] introduces @scheme[keyword-apply].}
|
||||
@guideother{@secref["apply"] introduces @racket[keyword-apply].}
|
||||
|
||||
@defexamples[
|
||||
#:eval greet-eval
|
||||
|
@ -207,9 +207,9 @@ remaining by-position arguments.
|
|||
@refdetails["lambda"]{function expressions}
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Arity-Sensitive Functions: @scheme[case-lambda]}
|
||||
@section{Arity-Sensitive Functions: @racket[case-lambda]}
|
||||
|
||||
The @scheme[case-lambda] form creates a function that can have
|
||||
The @racket[case-lambda] form creates a function that can have
|
||||
completely different behaviors depending on the number of arguments
|
||||
that are supplied. A case-lambda expression has the form
|
||||
|
||||
|
@ -222,9 +222,9 @@ that are supplied. A case-lambda expression has the form
|
|||
(arg-id ...+ . rest-id)])
|
||||
]
|
||||
|
||||
where each @scheme[[_formals _body ...+]] is analogous to @scheme[(lambda
|
||||
where each @racket[[_formals _body ...+]] is analogous to @racket[(lambda
|
||||
_formals _body ...+)]. Applying a function produced by
|
||||
@scheme[case-lambda] is like applying a @scheme[lambda] for the first
|
||||
@racket[case-lambda] is like applying a @racket[lambda] for the first
|
||||
case that matches the number of given arguments.
|
||||
|
||||
@defexamples[
|
||||
|
@ -238,7 +238,7 @@ case that matches the number of given arguments.
|
|||
(greet)
|
||||
]
|
||||
|
||||
A @scheme[case-lambda] function cannot directly support optional or
|
||||
A @racket[case-lambda] function cannot directly support optional or
|
||||
keyword arguments.
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
|
|
|
@ -5,24 +5,24 @@
|
|||
|
||||
@title[#:tag "let"]{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].
|
||||
Although internal @racket[define]s can be used for local binding,
|
||||
Racket provides three forms that give the programmer more
|
||||
control over bindings: @racket[let], @racket[let*], and
|
||||
@racket[letrec].
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Parallel Binding: @scheme[let]}
|
||||
@section{Parallel Binding: @racket[let]}
|
||||
|
||||
@refalso["let"]{@scheme[let]}
|
||||
@refalso["let"]{@racket[let]}
|
||||
|
||||
A @scheme[let] form binds a set of identifiers, each to the result of
|
||||
some expression, for use in the @scheme[let] body:
|
||||
A @racket[let] form binds a set of identifiers, each to the result of
|
||||
some expression, for use in the @racket[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
|
||||
The @racket[_id]s are bound ``in parallel.'' That is, no @racket[_id]
|
||||
is bound in the right-hand side @racket[_expr] for any @racket[_id],
|
||||
but all are available in the @racket[_body]. The @racket[_id]s must be
|
||||
different from each other.
|
||||
|
||||
@examples[
|
||||
|
@ -37,7 +37,7 @@ different from each other.
|
|||
me)
|
||||
]
|
||||
|
||||
The fact that an @scheme[_id]'s @scheme[_expr] does not see its own
|
||||
The fact that an @racket[_id]'s @racket[_expr] does not see its own
|
||||
binding is often useful for wrappers that must refer back to the old
|
||||
value:
|
||||
|
||||
|
@ -45,12 +45,12 @@ value:
|
|||
(let ([+ (lambda (x y)
|
||||
(if (string? x)
|
||||
(string-append x y)
|
||||
(+ x y)))]) (code:comment @#,t{use original @scheme[+]})
|
||||
(+ x y)))]) (code:comment @#,t{use original @racket[+]})
|
||||
(list (+ 1 2)
|
||||
(+ "see" "saw")))
|
||||
]
|
||||
|
||||
Occasionally, the parallel nature of @scheme[let] bindings is
|
||||
Occasionally, the parallel nature of @racket[let] bindings is
|
||||
convenient for swapping or rearranging a set of bindings:
|
||||
|
||||
@interaction[
|
||||
|
@ -61,23 +61,23 @@ convenient for swapping or rearranging a set of bindings:
|
|||
(list me you)))
|
||||
]
|
||||
|
||||
The characterization of @scheme[let] bindings as ``parallel'' is not
|
||||
meant to imply concurrent evaluation. The @scheme[_expr]s are
|
||||
The characterization of @racket[let] bindings as ``parallel'' is not
|
||||
meant to imply concurrent evaluation. The @racket[_expr]s are
|
||||
evaluated in order, even though the bindings are delayed until all
|
||||
@scheme[_expr]s are evaluated.
|
||||
@racket[_expr]s are evaluated.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Sequential Binding: @scheme[let*]}
|
||||
@section{Sequential Binding: @racket[let*]}
|
||||
|
||||
@refalso["let"]{@scheme[let*]}
|
||||
@refalso["let"]{@racket[let*]}
|
||||
|
||||
The syntax of @scheme[let*] is the same as @scheme[let]:
|
||||
The syntax of @racket[let*] is the same as @racket[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
|
||||
The difference is that each @racket[_id] is available for use in later
|
||||
@racket[_expr]s, as well as in the @racket[_body]. Furthermore, the
|
||||
@racket[_id]s need not be distinct, and the most recent binding is the
|
||||
visible one.
|
||||
|
||||
@examples[
|
||||
|
@ -91,8 +91,8 @@ visible one.
|
|||
name)
|
||||
]
|
||||
|
||||
In other words, a @scheme[let*] form is equivalent to nested
|
||||
@scheme[let] forms, each with a single binding:
|
||||
In other words, a @racket[let*] form is equivalent to nested
|
||||
@racket[let] forms, each with a single binding:
|
||||
|
||||
@interaction[
|
||||
(let ([name (list "Borroughs")])
|
||||
|
@ -102,22 +102,22 @@ In other words, a @scheme[let*] form is equivalent to nested
|
|||
]
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Recursive Binding: @scheme[letrec]}
|
||||
@section{Recursive Binding: @racket[letrec]}
|
||||
|
||||
@refalso["let"]{@scheme[letrec]}
|
||||
@refalso["let"]{@racket[letrec]}
|
||||
|
||||
The syntax of @scheme[letrec] is also the same as @scheme[let]:
|
||||
The syntax of @racket[letrec] is also the same as @racket[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.
|
||||
While @racket[let] makes its bindings available only in the
|
||||
@racket[_body]s, and @racket[let*] makes its bindings available to any
|
||||
later binding @racket[_expr], @racket[letrec] makes its bindings
|
||||
available to all other @racket[_expr]s---even earlier ones. In other
|
||||
words, @racket[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:
|
||||
The @racket[_expr]s in a @racket[letrec] form are most often
|
||||
@racket[lambda] forms for recursive and mutually recursive functions:
|
||||
|
||||
@interaction[
|
||||
(letrec ([swing
|
||||
|
@ -145,11 +145,11 @@ The @scheme[_expr]s in a @scheme[letrec] form are most often
|
|||
(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
|
||||
While the @racket[_expr]s of a @racket[letrec] form are typically
|
||||
@racket[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
|
||||
it is immediately associated with its corresponding @racket[_id]. If
|
||||
an @racket[_id] is referenced before its value is ready, the result is
|
||||
@|undefined-const|, as just as for internal definitions.
|
||||
|
||||
@interaction[
|
||||
|
@ -161,14 +161,14 @@ an @scheme[_id] is referenced before its value is ready, the result is
|
|||
@include-section["named-let.scrbl"]
|
||||
|
||||
@; ----------------------------------------
|
||||
@section{Multiple Values: @scheme[let-values], @scheme[let*-values], @scheme[letrec-values]}
|
||||
@section{Multiple Values: @racket[let-values], @racket[let*-values], @racket[letrec-values]}
|
||||
|
||||
@refalso["let"]{multiple-value binding forms}
|
||||
|
||||
In the same way that @scheme[define-values] binds multiple
|
||||
In the same way that @racket[define-values] binds multiple
|
||||
results in a definition (see @secref["multiple-values"]),
|
||||
@scheme[let-values], @scheme[let*-values], and
|
||||
@scheme[letrec-values] bind multiple results locally.
|
||||
@racket[let-values], @racket[let*-values], and
|
||||
@racket[letrec-values] bind multiple results locally.
|
||||
|
||||
@specform[(let-values ([(id ...) expr] ...)
|
||||
body ...+)]
|
||||
|
@ -177,13 +177,13 @@ results in a definition (see @secref["multiple-values"]),
|
|||
@specform[(letrec-values ([(id ...) expr] ...)
|
||||
body ...+)]
|
||||
|
||||
Each @scheme[_expr] must produce as many values as corresponding
|
||||
@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.
|
||||
Each @racket[_expr] must produce as many values as corresponding
|
||||
@racket[_id]s. The binding rules are the same for the forms
|
||||
without @racketkeywordfont{-values} forms: the @racket[_id]s of
|
||||
@racket[let-values] are bound only in the @racket[_body]s, the
|
||||
@racket[_id]s of @racket[let*-values]s are bound in
|
||||
@racket[_expr]s of later clauses, and the @racket[_id]s of
|
||||
@racket[letrec-value]s are bound for all @racket[_expr]s.
|
||||
|
||||
@examples[
|
||||
(let-values ([(q r) (quotient/remainder 14 3)])
|
||||
|
|
|
@ -2,35 +2,35 @@
|
|||
@(require scribble/manual
|
||||
scribble/eval
|
||||
scribble/bnf
|
||||
scheme/list
|
||||
(for-label scheme/list)
|
||||
racket/list
|
||||
(for-label racket/list)
|
||||
"guide-utils.ss")
|
||||
|
||||
@(define step @elem{=})
|
||||
|
||||
@(define list-eval (make-base-eval))
|
||||
@(interaction-eval #:eval list-eval (require scheme/list))
|
||||
@(interaction-eval #:eval list-eval (require racket/list))
|
||||
|
||||
@title{Lists, Iteration, and Recursion}
|
||||
|
||||
Scheme is a dialect of the language Lisp, whose name originally stood
|
||||
Racket 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] function takes any number of values and returns
|
||||
The @racket[list] function 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 @tech{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")]. Remember that, in the documentation and in
|
||||
DrScheme, parentheses for results are printed in blue, whereas
|
||||
parentheses for expressions are brown.
|
||||
As you can see, a list result prints in the @tech{REPL} as a backquote
|
||||
@litchar{`} and then 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
|
||||
@racket[(list "red" "green" "blue")], and printed results, such as
|
||||
@racketresult['("red" "green" "blue")]. In addition to the backquote,
|
||||
parentheses for results are printed in blue in the documentation and
|
||||
in DrRacket, whereas parentheses for expressions are brown.
|
||||
|
||||
Many predefined functions operate on lists. Here are a few examples:
|
||||
|
||||
|
@ -46,15 +46,15 @@ Many predefined functions operate on lists. Here are a few examples:
|
|||
@;------------------------------------------------------------------------
|
||||
@section{Predefined List Loops}
|
||||
|
||||
In addition to simple operations like @scheme[append], Scheme includes
|
||||
In addition to simple operations like @racket[append], Racket includes
|
||||
functions that iterate over the elements of a list. These iteration
|
||||
functions play much the same role as @tt{for} in Java and other
|
||||
languages. The body of a Scheme iteration is packaged into a function
|
||||
to be applied to each element, so the @scheme[lambda] form becomes
|
||||
functions play a role similar to @racket[for] in Java, Racket, and other
|
||||
languages. The body of a Racket iteration is packaged into a function
|
||||
to be applied to each element, so the @racket[lambda] form becomes
|
||||
particularly handy in combination with iteration functions.
|
||||
|
||||
Different list-iteration functions combine iteration results in
|
||||
different ways. The @scheme[map] function uses the per-element
|
||||
different ways. The @racket[map] function uses the per-element
|
||||
results to create a new list:
|
||||
|
||||
@interaction[
|
||||
|
@ -64,8 +64,8 @@ results to create a new list:
|
|||
(list "peanuts" "popcorn" "crackerjack"))
|
||||
]
|
||||
|
||||
The @scheme[andmap] and @scheme[ormap] functions combine the results
|
||||
by @scheme[and]ing or @scheme[or]ing:
|
||||
The @racket[andmap] and @racket[ormap] functions combine the results
|
||||
by @racket[and]ing or @racket[or]ing:
|
||||
|
||||
@interaction[
|
||||
(andmap string? (list "a" "b" "c"))
|
||||
|
@ -73,15 +73,15 @@ by @scheme[and]ing or @scheme[or]ing:
|
|||
(ormap number? (list "a" "b" 6))
|
||||
]
|
||||
|
||||
The @scheme[filter] function keeps elements for which the body result
|
||||
is true, and discards elements for which it is @scheme[#f]:
|
||||
The @racket[filter] function keeps elements for which the body result
|
||||
is true, and discards elements for which it is @racket[#f]:
|
||||
|
||||
@interaction[
|
||||
(filter string? (list "a" "b" 6))
|
||||
(filter positive? (list 1 -2 6 7 0))
|
||||
]
|
||||
|
||||
The @scheme[map], @scheme[andmap], @scheme[ormap], and @scheme[filter]
|
||||
The @racket[map], @racket[andmap], @racket[ormap], and @racket[filter]
|
||||
functions can all handle multiple lists, instead of just a single
|
||||
list. The lists must all have the same length, and the given function
|
||||
must accept one argument for each list:
|
||||
|
@ -92,7 +92,7 @@ must accept one argument for each list:
|
|||
(list 6 3 7))
|
||||
]
|
||||
|
||||
The @scheme[foldl] function generalizes some iteration functions. It
|
||||
The @racket[foldl] function generalizes some iteration functions. It
|
||||
uses the per-element function to both process an element and combine
|
||||
it with the ``current'' value, so the per-element function takes an
|
||||
extra first argument. Also, a starting ``current'' value must be
|
||||
|
@ -105,31 +105,31 @@ provided before the lists:
|
|||
'(1 2 3))
|
||||
]
|
||||
|
||||
Despite its generality, @scheme[foldl] is not as popular as the other
|
||||
functions. One reason is that @scheme[map], @scheme[ormap],
|
||||
@scheme[andmap], and @scheme[filter] cover the most common kinds of
|
||||
Despite its generality, @racket[foldl] is not as popular as the other
|
||||
functions. One reason is that @racket[map], @racket[ormap],
|
||||
@racket[andmap], and @racket[filter] cover the most common kinds of
|
||||
list loops.
|
||||
|
||||
Scheme provides a general @defterm{list comprehension} form
|
||||
@scheme[for/list], which builds a list by iterating through
|
||||
Racket provides a general @defterm{list comprehension} form
|
||||
@racket[for/list], which builds a list by iterating through
|
||||
@defterm{sequences}. List comprehensions and related iteration forms
|
||||
are described in see @secref["for"].
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{List Iteration from Scratch}
|
||||
|
||||
Although @scheme[map] and other iteration functions predefined, they
|
||||
Although @racket[map] and other iteration functions predefined, they
|
||||
are not primitive in any interesting sense. You can write equivalent
|
||||
iterations using a handful of list primitives.
|
||||
|
||||
Since a Scheme list is a linked list, the two core operations on a
|
||||
Since a Racket list is a linked list, the two core operations on a
|
||||
non-empty list are
|
||||
|
||||
@itemize[
|
||||
|
||||
@item{@scheme[first]: get the first thing in the list; and}
|
||||
@item{@racket[first]: get the first thing in the list; and}
|
||||
|
||||
@item{@scheme[rest]: get the rest of the list.}
|
||||
@item{@racket[rest]: get the rest of the list.}
|
||||
|
||||
]
|
||||
|
||||
|
@ -140,9 +140,9 @@ non-empty list are
|
|||
]
|
||||
|
||||
To create a new node for a linked list---that is, to add to the front
|
||||
of the list---use the @scheme[cons] function, which is short for
|
||||
of the list---use the @racket[cons] function, which is short for
|
||||
``construct.'' To get an empty list to start with, use the
|
||||
@scheme[empty] constant:
|
||||
@racket[empty] constant:
|
||||
|
||||
@interaction[
|
||||
#:eval list-eval
|
||||
|
@ -152,9 +152,9 @@ empty
|
|||
]
|
||||
|
||||
To process a list, you need to be able to distinguish empty lists from
|
||||
non-empty lists, because @scheme[first] and @scheme[rest] work only on
|
||||
non-empty lists. The @scheme[empty?] function detects empty lists,
|
||||
and @scheme[cons?] detects non-empty lists:
|
||||
non-empty lists, because @racket[first] and @racket[rest] work only on
|
||||
non-empty lists. The @racket[empty?] function detects empty lists,
|
||||
and @racket[cons?] detects non-empty lists:
|
||||
|
||||
@interaction[
|
||||
#:eval list-eval
|
||||
|
@ -165,7 +165,7 @@ and @scheme[cons?] detects non-empty lists:
|
|||
]
|
||||
|
||||
With these pieces, you can write your own versions of the
|
||||
@scheme[length] function, @scheme[map] function, and more.
|
||||
@racket[length] function, @racket[map] function, and more.
|
||||
|
||||
@defexamples[
|
||||
#:eval list-eval
|
||||
|
@ -193,11 +193,11 @@ of recursive calls instead of a looping construct, then read on.
|
|||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "tail-recursion"]{Tail Recursion}
|
||||
|
||||
Both the @scheme[my-length] and @scheme[my-map] functions run in
|
||||
Both the @racket[my-length] and @racket[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:
|
||||
imagining how @racket[(my-length (list "a" "b" "c"))] must evaluate:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
#||# (my-length (list "a" "b" "c"))
|
||||
#,step (+ 1 (my-length (list "b" "c")))
|
||||
#,step (+ 1 (+ 1 (my-length (list "c"))))
|
||||
|
@ -209,29 +209,29 @@ imagining how @scheme[(my-length (list "a" "b" "c"))] must evaluate:
|
|||
]
|
||||
|
||||
For a list with @math{n} elements, evaluation will stack up @math{n}
|
||||
@scheme[(+ 1 ...)] additions, and then finally add them up when the
|
||||
@racket[(+ 1 ...)] additions, and then finally add them up when the
|
||||
list is exhausted.
|
||||
|
||||
You can avoid piling up additions by adding along the way. To
|
||||
accumulate a length this way, we need a function that takes both a
|
||||
list and the length of the list seem so far; the code below uses a
|
||||
local function @scheme[iter] that accumulates the length in an
|
||||
argument @scheme[len]:
|
||||
local function @racket[iter] that accumulates the length in an
|
||||
argument @racket[len]:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define (my-length lst)
|
||||
(code:comment @#,t{local function @scheme[iter]:})
|
||||
(code:comment @#,t{local function @racket[iter]:})
|
||||
(define (iter lst len)
|
||||
(cond
|
||||
[(empty? lst) len]
|
||||
[else (iter (rest lst) (+ len 1))]))
|
||||
(code:comment @#,t{body of @scheme[my-length] calls @scheme[iter]:})
|
||||
(code:comment @#,t{body of @racket[my-length] calls @racket[iter]:})
|
||||
(iter lst 0))
|
||||
]
|
||||
|
||||
Now evaluation looks like this:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
#||# (my-length (list "a" "b" "c"))
|
||||
#,step (iter (list "a" "b" "c") 0)
|
||||
#,step (iter (list "b" "c") 1)
|
||||
|
@ -240,21 +240,21 @@ Now evaluation looks like this:
|
|||
3
|
||||
]
|
||||
|
||||
The revised @scheme[my-length] runs in constant space, just as the
|
||||
The revised @racket[my-length] runs in constant space, just as the
|
||||
evaluation steps above suggest. That is, when the result of a
|
||||
function call, like @scheme[(iter (list "b" "c") 1)], is exactly the
|
||||
result of some other function call, like @scheme[(iter (list "c")
|
||||
function call, like @racket[(iter (list "b" "c") 1)], is exactly the
|
||||
result of some other function call, like @racket[(iter (list "c")
|
||||
2)], then the first one doesn't have to wait around for the second
|
||||
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
|
||||
optimization}, but it's not merely an ``optimization'' in Racket; it's
|
||||
a guarantee about the way the code will run. More precisely, an
|
||||
expression in @idefterm{tail position} with respect to another
|
||||
expression in @deftech{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
|
||||
In the case of @racket[my-map], @math{O(n)} space complexity is
|
||||
reasonable, since it has to generate a result of size
|
||||
@math{O(n)}. Nevertheless, you can reduce the constant factor by
|
||||
accumulating the result list. The only catch is that the accumulated
|
||||
|
@ -263,7 +263,7 @@ list will be backwards, so you'll have to reverse it at the very end:
|
|||
@margin-note{Attempting to reduce a constant factor like this is
|
||||
usually not worthwhile, as discussed below.}
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define (my-map f lst)
|
||||
(define (iter lst backward-result)
|
||||
(cond
|
||||
|
@ -276,40 +276,40 @@ usually not worthwhile, as discussed below.}
|
|||
|
||||
It turns out that if you write
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define (my-map f lst)
|
||||
(for/list ([i lst])
|
||||
(f i)))
|
||||
]
|
||||
|
||||
then the @scheme[for/list] form in the function both is expanded to
|
||||
essentially the same code as the @scheme[iter] local definition and
|
||||
then the @racket[for/list] form in the function both is expanded to
|
||||
essentially the same code as the @racket[iter] local definition and
|
||||
use. The difference is merely syntactic convenience.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Recursion versus Iteration}
|
||||
|
||||
The @scheme[my-length] and @scheme[my-map] examples demonstrate that
|
||||
The @racket[my-length] and @racket[my-map] examples demonstrate that
|
||||
iteration is just a special case of recursion. In many languages, it's
|
||||
important to try to fit as many computations as possible into
|
||||
iteration form. Otherwise, performance will be bad, and moderately
|
||||
large inputs can lead to stack overflow. Similarly, in Scheme, it is
|
||||
large inputs can lead to stack overflow. Similarly, in Racket, it is
|
||||
sometimes important to make sure that tail recursion is used to avoid
|
||||
@math{O(n)} space consumption when the computation is easily performed
|
||||
in constant space.
|
||||
|
||||
At the same time, recursion does not lead to particularly bad
|
||||
performance in Scheme, and there is no such thing as stack overflow;
|
||||
performance in Racket, and there is no such thing as stack overflow;
|
||||
you can run out of memory if a computation involves too much context,
|
||||
but exhausting memory typically requires orders of magnitude deeper
|
||||
recursion than would trigger a stack overflow in other
|
||||
languages. These considerations, combined with the fact that
|
||||
tail-recursive programs automatically run the same as a loop, lead
|
||||
Scheme programmers to embrace recursive forms rather than avoid them.
|
||||
Racket programmers to embrace recursive forms rather than avoid them.
|
||||
|
||||
Suppose, for example, that you want to remove consecutive duplicates
|
||||
from a list. While such a function can be written as a loop that
|
||||
remembers the previous element for each iteration, a Scheme programmer
|
||||
remembers the previous element for each iteration, a Racket programmer
|
||||
would more likely just write the following:
|
||||
|
||||
@def+int[
|
||||
|
@ -330,12 +330,12 @@ In general, this function consumes @math{O(n)} space for an input
|
|||
list of length @math{n}, but that's fine, since it produces an
|
||||
@math{O(n)} result. If the input list happens to be mostly consecutive
|
||||
duplicates, then the resulting list can be much smaller than
|
||||
@math{O(n)}---and @scheme[remove-dups] will also use much less than
|
||||
@math{O(n)}---and @racket[remove-dups] will also use much less than
|
||||
@math{O(n)} space! The reason is that when the function discards
|
||||
duplicates, it returns the result of a @scheme[remove-dups] call
|
||||
duplicates, it returns the result of a @racket[remove-dups] call
|
||||
directly, so the tail-call ``optimization'' kicks in:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
#||# (remove-dups (list "a" "b" "b" "b" "b" "b"))
|
||||
#,step (cons "a" (remove-dups (list "b" "b" "b" "b" "b")))
|
||||
#,step (cons "a" (remove-dups (list "b" "b" "b" "b")))
|
||||
|
|
|
@ -6,17 +6,17 @@
|
|||
|
||||
@title[#:tag "module-basics"]{Module Basics}
|
||||
|
||||
The space of module names is distinct from the space of normal Scheme
|
||||
The space of module names is distinct from the space of normal Racket
|
||||
definitions. Indeed, since modules typically reside in files, the
|
||||
space of module names is explicitly tied to the filesystem at run
|
||||
time. For example, if the file @filepath{/home/molly/cake.ss} contains
|
||||
time. For example, if the file @filepath{/home/molly/cake.rkt} contains
|
||||
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
|
||||
(provide print-cake)
|
||||
|
||||
(code:comment @#,t{draws a cake with @scheme[n] candles})
|
||||
(code:comment @#,t{draws a cake with @racket[n] candles})
|
||||
(define (print-cake n)
|
||||
(printf " ~a \n" (make-string n #\.))
|
||||
(printf " .-~a-.\n" (make-string n #\|))
|
||||
|
@ -25,40 +25,40 @@ scheme
|
|||
]
|
||||
|
||||
then it can be used as the source of a module whose full name is based
|
||||
on the path @filepath{/home/molly/cake.ss}. The @scheme[provide] line
|
||||
exports the definition @scheme[print-cake] so that it can be used
|
||||
on the path @filepath{/home/molly/cake.rkt}. The @racket[provide] line
|
||||
exports the definition @racket[print-cake] so that it can be used
|
||||
outside the module.
|
||||
|
||||
Instead of using its full path, a module is more likely to be
|
||||
referenced by a relative path. For example, a file
|
||||
@filepath{/home/molly/random-cake.ss} could use the @filepath{cake.ss} module
|
||||
@filepath{/home/molly/random-cake.rkt} could use the @filepath{cake.rkt} module
|
||||
like this:
|
||||
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
|
||||
(require "cake.ss")
|
||||
(require "cake.rkt")
|
||||
|
||||
(print-cake (random 30))
|
||||
]
|
||||
|
||||
The relative reference @scheme["cake.ss"] in the import
|
||||
@scheme[(require "cake.ss")] works because the @filepath{cake.ss} module
|
||||
source is in the same directory as the @filepath{random-cake.ss}
|
||||
The relative reference @racket["cake.rkt"] in the import
|
||||
@racket[(require "cake.rkt")] works because the @filepath{cake.rkt} module
|
||||
source is in the same directory as the @filepath{random-cake.rkt}
|
||||
file. (Unix-style relative paths are used for relative module
|
||||
references on all platforms, much like relative URLs.)
|
||||
|
||||
Library modules that are distributed with PLT Scheme are usually
|
||||
Library modules that are distributed with Racket are usually
|
||||
referenced through an unquoted, suffixless path. The path is relative
|
||||
to the library installation directory, which contains directories for
|
||||
individual library @deftech{collections}. The module below refers to
|
||||
the @filepath{date.ss} library that is part of the @filepath{scheme}
|
||||
the @filepath{date.rkt} library that is part of the @filepath{racket}
|
||||
@tech{collection}.
|
||||
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
|
||||
(require scheme/date)
|
||||
(require racket/date)
|
||||
|
||||
(printf "Today is ~s\n"
|
||||
(date->string (seconds->date (current-seconds))))
|
||||
|
@ -71,8 +71,8 @@ collection directories can be specified in configuration files or
|
|||
through the @envvar{PLTCOLLECTS} search path. Try running the
|
||||
following program to find out where your collections are:
|
||||
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
|
||||
(require setup/dirs)
|
||||
|
||||
|
|
|
@ -6,92 +6,104 @@
|
|||
@title[#:tag "module-paths"]{Module Paths}
|
||||
|
||||
A @deftech{module path} is a reference to a module, as used with
|
||||
@scheme[require] or as the @scheme[_initial-module-path] in a
|
||||
@scheme[module] form. It can be any of several forms:
|
||||
@racket[require] or as the @racket[_initial-module-path] in a
|
||||
@racket[module] form. It can be any of several forms:
|
||||
|
||||
@; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@specsubform[#:literals (quote) (#,(scheme quote) id)]{
|
||||
@specsubform[#:literals (quote) (#,(racket quote) id)]{
|
||||
|
||||
A @tech{module path} that is a quoted identifier refers to a non-file
|
||||
@scheme[module] declaration using the identifier. This form of module
|
||||
@racket[module] declaration using the identifier. This form of module
|
||||
reference makes the most sense in a @tech{REPL}.
|
||||
|
||||
@examples[
|
||||
(module m scheme
|
||||
(module m racket
|
||||
(provide color)
|
||||
(define color "blue"))
|
||||
(module n scheme
|
||||
(module n racket
|
||||
(require 'm)
|
||||
(printf "my favorite color is ~a\n" color))
|
||||
(require 'n)
|
||||
]}
|
||||
|
||||
@; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@specsubform[id]{
|
||||
|
||||
A @tech{module path} that is an unquoted identifier refers to an
|
||||
installed library. The @scheme[id] is constrained to contain only
|
||||
ASCII letters, ASCII numbers, @litchar{+}, @litchar{-}, @litchar{_},
|
||||
and @litchar{/}, where @litchar{/} separates path elements within the
|
||||
identifier. The elements refer to @tech{collection}s and
|
||||
sub-@tech{collections}, instead of directories and sub-directories.
|
||||
|
||||
An example of this form is @scheme[scheme/date]. It refers to the
|
||||
module whose source is the @filepath{date.ss} file in the
|
||||
@filepath{scheme} collection, which is installed as part of PLT
|
||||
Scheme. The @filepath{.ss} suffix is added automatically.
|
||||
|
||||
Another example of this form is @scheme[scheme], which is commonly
|
||||
used at the initial import. The path @scheme[scheme] is shorthand for
|
||||
@scheme[scheme/main]; when an @scheme[id] has no @litchar{/}, then
|
||||
@scheme[/main] is automatically added to the end. Thus,
|
||||
@scheme[scheme] or @scheme[scheme/main] refers to the module whose
|
||||
source is the @filepath{main.ss} file in the @filepath{scheme}
|
||||
collection.
|
||||
|
||||
@examples[
|
||||
(module m scheme
|
||||
(require scheme/date)
|
||||
|
||||
(printf "Today is ~s\n"
|
||||
(date->string (seconds->date (current-seconds)))))
|
||||
(require 'm)
|
||||
]}
|
||||
|
||||
@; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@specsubform[rel-string]{
|
||||
|
||||
A string @tech{module path} is a relative path using Unix-style
|
||||
conventions: @litchar{/} is the path separator, @litchar{..} refers to
|
||||
the parent directory, and @litchar{.} refers to the same
|
||||
directory. The @scheme[rel-string] must not start or end with a path
|
||||
separator.
|
||||
directory. The @racket[rel-string] must not start or end with a path
|
||||
separator. If the path has no suffix, @filepath{.rkt} is added
|
||||
automatically.
|
||||
|
||||
The path is relative to the enclosing file, if any, or it is relative
|
||||
to the current directory. (More precisely, the path is relative to the
|
||||
value of @scheme[(current-load-relative-directory)], which is set
|
||||
value of @racket[(current-load-relative-directory)], which is set
|
||||
while loading a file.)
|
||||
|
||||
@secref["module-basics"] shows examples using relative paths.
|
||||
}
|
||||
|
||||
If a relative path ends with a @filepath{.ss} suffix, it is converted
|
||||
to @filepath{.rkt}. If the file that implements the referenced module
|
||||
actually ends in @filepath{.ss}, the suffix will be changed back when
|
||||
attempting to load the file (but a @filepath{.rkt} suffix takes
|
||||
precedence). This two-way conversion provides compatibility with older
|
||||
versions of Racket.}
|
||||
|
||||
@; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@specsubform[id]{
|
||||
|
||||
A @tech{module path} that is an unquoted identifier refers to an
|
||||
installed library. The @racket[id] is constrained to contain only
|
||||
ASCII letters, ASCII numbers, @litchar{+}, @litchar{-}, @litchar{_},
|
||||
and @litchar{/}, where @litchar{/} separates path elements within the
|
||||
identifier. The elements refer to @tech{collection}s and
|
||||
sub-@tech{collections}, instead of directories and sub-directories.
|
||||
|
||||
An example of this form is @racket[racket/date]. It refers to the
|
||||
module whose source is the @filepath{date.rkt} file in the
|
||||
@filepath{racket} collection, which is installed as part of
|
||||
Racket. The @filepath{.rkt} suffix is added automatically.
|
||||
|
||||
Another example of this form is @racketmodname[racket], which is commonly
|
||||
used at the initial import. The path @racketmodname[racket] is shorthand for
|
||||
@racket[racket/main]; when an @racket[id] has no @litchar{/}, then
|
||||
@racket[/main] is automatically added to the end. Thus,
|
||||
@racketmodname[racket] or @racket[racket/main] refers to the module whose
|
||||
source is the @filepath{main.rkt} file in the @filepath{racket}
|
||||
collection.
|
||||
|
||||
@examples[
|
||||
(module m racket
|
||||
(require racket/date)
|
||||
|
||||
(printf "Today is ~s\n"
|
||||
(date->string (seconds->date (current-seconds)))))
|
||||
(require 'm)
|
||||
]
|
||||
|
||||
When the full path of a module ends with @filepath{.rkt}, if no such
|
||||
file exists but one does exist with the @filepath{.ss} suffix, then
|
||||
the @filepath{.ss} suffix is substituted automatically. This
|
||||
transformation provides compatibility with older versions of Racket.}
|
||||
|
||||
@; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@specsubform[#:literals (lib)
|
||||
(lib rel-string)]{
|
||||
|
||||
Like an unquoted-identifier path, but expressed as a string instead of
|
||||
an identifier. Also, the @scheme[rel-string] can end with a file
|
||||
suffix, in case the relevant suffix is not @filepath{.ss}.
|
||||
an identifier. Also, the @racket[rel-string] can end with a file
|
||||
suffix, in which case @filepath{.rkt} is not automatically added.
|
||||
|
||||
Example of this form include @scheme[(lib "scheme/date.ss")] and
|
||||
@scheme[(lib "scheme/date")], which are equivalent to
|
||||
@scheme[scheme/date]. Other examples include @scheme[(lib "scheme")],
|
||||
@scheme[(lib "scheme/main")], and @scheme[(lib "scheme/main.ss")],
|
||||
which are all equivalent to @scheme[scheme].
|
||||
Example of this form include @racket[(lib "racket/date.rkt")] and
|
||||
@racket[(lib "racket/date")], which are equivalent to
|
||||
@racket[racket/date]. Other examples include @racket[(lib "racket")],
|
||||
@racket[(lib "racket/main")], and @racket[(lib "racket/main.rkt")],
|
||||
which are all equivalent to @racketmodname[racket].
|
||||
|
||||
@examples[
|
||||
(module m (lib "scheme")
|
||||
(require (lib "scheme/date.ss"))
|
||||
(module m (lib "racket")
|
||||
(require (lib "racket/date.rkt"))
|
||||
|
||||
(printf "Today is ~s\n"
|
||||
(date->string (seconds->date (current-seconds)))))
|
||||
|
@ -106,17 +118,17 @@ Accesses a third-party library that is distributed through the
|
|||
@|PLaneT| server. The library is downloaded the first time that it is
|
||||
needed, and then the local copy is used afterward.
|
||||
|
||||
The @scheme[id] encodes several pieces of information separated by a
|
||||
The @racket[id] encodes several pieces of information separated by a
|
||||
@litchar{/}: the package owner, then package name with optional
|
||||
version information, and an optional path to a specific library with
|
||||
the package. Like @scheme[id] as shorthand for a @scheme[lib] path, a
|
||||
@filepath{.ss} suffix is added automatically, and @schemeidfont{/main}
|
||||
the package. Like @racket[id] as shorthand for a @racket[lib] path, a
|
||||
@filepath{.rkt} suffix is added automatically, and @racketidfont{/main}
|
||||
is used as the path if no sub-path element is supplied.
|
||||
|
||||
@examples[
|
||||
(eval:alts
|
||||
(module m (lib "scheme")
|
||||
(code:comment @#,t{Use @filepath{schematics}'s @filepath{random.plt} 1.0, file @filepath{random.ss}:})
|
||||
(module m (lib "racket")
|
||||
(code:comment @#,t{Use @filepath{schematics}'s @filepath{random.plt} 1.0, file @filepath{random.rkt}:})
|
||||
(require (planet schematics/random:1/random))
|
||||
(display (random-gaussian)))
|
||||
(void))
|
||||
|
@ -124,16 +136,23 @@ is used as the path if no sub-path element is supplied.
|
|||
(require 'm)
|
||||
(display 0.9050686838895684))
|
||||
]
|
||||
}
|
||||
|
||||
As with other forms, an implementation file ending with @filepath{.ss}
|
||||
can be substituted automatically if no implementation file ending with
|
||||
@filepath{.rkt} exists.}
|
||||
|
||||
@; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@specsubform[#:literals (planet)
|
||||
(planet package-string)]{
|
||||
|
||||
Like the symbol form of a @scheme[planet], but using a string instead
|
||||
of an identifier. Also, the @scheme[package-string] can end with a
|
||||
file suffix, in case the relevant suffix is not @filepath{.ss}.
|
||||
}
|
||||
Like the symbol form of a @racket[planet], but using a string instead
|
||||
of an identifier. Also, the @racket[package-string] can end with a
|
||||
file suffix, in which case @filepath{.rkt} is not added.
|
||||
|
||||
As with other forms, an @filepath{.ss} extension is converted to
|
||||
@filepath{.rkt}, while an implementation file ending with
|
||||
@filepath{.ss} can be substituted automatically if no implementation
|
||||
file ending with @filepath{.rkt} exists.}
|
||||
|
||||
@; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@specsubform/subs[#:literals (planet = + -)
|
||||
|
@ -145,45 +164,48 @@ file suffix, in case the relevant suffix is not @filepath{.ss}.
|
|||
(- nat)])]{
|
||||
|
||||
A more general form to access a library from the @|PLaneT| server. In
|
||||
this general form, a @|PLaneT| reference starts like a @scheme[lib]
|
||||
this general form, a @|PLaneT| reference starts like a @racket[lib]
|
||||
reference with a relative path, but the path is followed by
|
||||
information about the producer, package, and version of the
|
||||
library. The specified package is downloaded and installed on demand.
|
||||
|
||||
The @scheme[vers]es specify a constraint on the acceptable version of
|
||||
The @racket[vers]es specify a constraint on the acceptable version of
|
||||
the package, where a version number is a sequence of non-negative
|
||||
integers, and the constraints determine the allowable values for each
|
||||
element in the sequence. If no constraint is provided for a particular
|
||||
element, then any version is allowed; in particular, omitting all
|
||||
@scheme[vers]es means that any version is acceptable. Specifying at
|
||||
least one @scheme[vers] is strongly recommended.
|
||||
@racket[vers]es means that any version is acceptable. Specifying at
|
||||
least one @racket[vers] is strongly recommended.
|
||||
|
||||
For a version constraint, a plain @scheme[nat] is the same as
|
||||
@scheme[(+ nat)], which matches @scheme[nat] or higher for the
|
||||
corresponding element of the version number. A @scheme[(_start-nat
|
||||
_end-nat)] matches any number in the range @scheme[_start-nat] to
|
||||
@scheme[_end-nat], inclusive. A @scheme[(= nat)] matches only exactly
|
||||
@scheme[nat]. A @scheme[(- nat)] matches @scheme[nat] or lower.
|
||||
For a version constraint, a plain @racket[nat] is the same as
|
||||
@racket[(+ nat)], which matches @racket[nat] or higher for the
|
||||
corresponding element of the version number. A @racket[(_start-nat
|
||||
_end-nat)] matches any number in the range @racket[_start-nat] to
|
||||
@racket[_end-nat], inclusive. A @racket[(= nat)] matches only exactly
|
||||
@racket[nat]. A @racket[(- nat)] matches @racket[nat] or lower.
|
||||
|
||||
@examples[
|
||||
(eval:alts
|
||||
(module m (lib "scheme")
|
||||
(require (planet "random.ss" ("schematics" "random.plt" 1 0)))
|
||||
(module m (lib "racket")
|
||||
(require (planet "random.rkt" ("schematics" "random.plt" 1 0)))
|
||||
(display (random-gaussian)))
|
||||
(void))
|
||||
(eval:alts
|
||||
(require 'm)
|
||||
(display 0.9050686838895684))
|
||||
]
|
||||
}
|
||||
|
||||
The automatic @filepath{.ss} and @filepath{.rkt} conversions apply as
|
||||
with other forms.}
|
||||
|
||||
@; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@specsubform[#:literals (file)
|
||||
(file string)]{
|
||||
|
||||
Refers to a file, where @scheme[string] is a relative or absolute path
|
||||
Refers to a file, where @racket[string] is a relative or absolute path
|
||||
using the current platform's conventions. This form is not portable,
|
||||
and it should @italic{not} be used when a plain, portable
|
||||
@scheme[rel-string] suffices.
|
||||
@racket[rel-string] suffices.
|
||||
|
||||
}
|
||||
The automatic @filepath{.ss} and @filepath{.rkt} conversions apply as
|
||||
with other forms.}
|
||||
|
|
|
@ -3,31 +3,31 @@
|
|||
scribble/eval
|
||||
"guide-utils.ss")
|
||||
|
||||
@title[#:tag "module-provide"]{Exports: @scheme[provide]}
|
||||
@title[#:tag "module-provide"]{Exports: @racket[provide]}
|
||||
|
||||
By default, all of a module's definitions are private to the
|
||||
module. The @scheme[provide] form specifies definitions to be made
|
||||
available where the module is @scheme[require]d.
|
||||
module. The @racket[provide] form specifies definitions to be made
|
||||
available where the module is @racket[require]d.
|
||||
|
||||
@specform[(provide provide-spec ...)]{}
|
||||
|
||||
A @scheme[provide] form can only appear at module level (i.e., in the
|
||||
immediate body of a @scheme[module]). Specifying multiple
|
||||
@scheme[_provide-spec]s in a single @scheme[provide] is exactly the
|
||||
same as using multiple @scheme[provide]s each with a single
|
||||
@scheme[_provide-spec].
|
||||
A @racket[provide] form can only appear at module level (i.e., in the
|
||||
immediate body of a @racket[module]). Specifying multiple
|
||||
@racket[_provide-spec]s in a single @racket[provide] is exactly the
|
||||
same as using multiple @racket[provide]s each with a single
|
||||
@racket[_provide-spec].
|
||||
|
||||
Each identifier can be exported at most once from a module across all
|
||||
@scheme[provide]s within the module. More precisely, the external name
|
||||
@racket[provide]s within the module. More precisely, the external name
|
||||
for each export must be distinct; the same internal binding can be
|
||||
exported multiple times with different external names.
|
||||
|
||||
The allowed shape of a @scheme[_provide-spec] is defined recursively:
|
||||
The allowed shape of a @racket[_provide-spec] is defined recursively:
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@specspecsubform[identifier]{
|
||||
|
||||
In its simplest form, a @scheme[_provide-spec] indicates a binding
|
||||
In its simplest form, a @racket[_provide-spec] indicates a binding
|
||||
within its module to be exported. The binding can be from either a
|
||||
local definition, or from an import.
|
||||
|
||||
|
@ -37,9 +37,9 @@ local definition, or from an import.
|
|||
@specspecsubform[#:literals(rename-out)
|
||||
(rename-out [orig-id export-id] ...)]{
|
||||
|
||||
A @scheme[rename-out] form is similar to just specifying an identifier,
|
||||
but the exported binding @scheme[orig-id] is given a different name,
|
||||
@scheme[export-id], to importing modules.
|
||||
A @racket[rename-out] form is similar to just specifying an identifier,
|
||||
but the exported binding @racket[orig-id] is given a different name,
|
||||
@racket[export-id], to importing modules.
|
||||
|
||||
}
|
||||
|
||||
|
@ -48,11 +48,11 @@ but the exported binding @scheme[orig-id] is given a different name,
|
|||
@specspecsubform[#:literals(struct-out)
|
||||
(struct-out struct-id)]{
|
||||
|
||||
A @scheme[struct-out] form exports the bindings created by
|
||||
@scheme[(define-struct struct-id ....)].
|
||||
A @racket[struct-out] form exports the bindings created by
|
||||
@racket[(struct struct-id ....)].
|
||||
|
||||
@guideother{See @secref["define-struct"] for information on
|
||||
@scheme[define-struct].}
|
||||
@racket[define-struct].}
|
||||
|
||||
}
|
||||
|
||||
|
@ -61,15 +61,15 @@ A @scheme[struct-out] form exports the bindings created by
|
|||
@specspecsubform[#:literals (all-defined-out)
|
||||
(all-defined-out)]{
|
||||
|
||||
The @scheme[all-defined-out] shorthand exports all bindings that are
|
||||
The @racket[all-defined-out] shorthand exports all bindings that are
|
||||
defined within the exporting module (as opposed to imported).
|
||||
|
||||
Use of the @scheme[all-defined-out] shorthand is generally
|
||||
Use of the @racket[all-defined-out] shorthand is generally
|
||||
discouraged, because it makes less clear the actual exports for a
|
||||
module, and because PLT Scheme programmers get into the habit of
|
||||
module, and because Racket programmers get into the habit of
|
||||
thinking that definitions can be added freely to a module without
|
||||
affecting its public interface (which is not the case when
|
||||
@scheme[all-defined-out] is used).
|
||||
@racket[all-defined-out] is used).
|
||||
|
||||
}
|
||||
|
||||
|
@ -77,13 +77,13 @@ affecting its public interface (which is not the case when
|
|||
@specspecsubform[#:literals (all-from-out)
|
||||
(all-from-out module-path)]{
|
||||
|
||||
The @scheme[all-from-out] shorthand exports all bindings in the module
|
||||
that were imported using a @scheme[_require-spec] that is based on
|
||||
@scheme[module-path].
|
||||
The @racket[all-from-out] shorthand exports all bindings in the module
|
||||
that were imported using a @racket[_require-spec] that is based on
|
||||
@racket[module-path].
|
||||
|
||||
Although different @scheme[module-path]s could refer to the same
|
||||
file-based module, re-exporting with @scheme[all-from-out] is based
|
||||
specifically on the @scheme[module-path] reference, and not the module
|
||||
Although different @racket[module-path]s could refer to the same
|
||||
file-based module, re-exporting with @racket[all-from-out] is based
|
||||
specifically on the @racket[module-path] reference, and not the module
|
||||
that is actually referenced.
|
||||
|
||||
}
|
||||
|
@ -92,8 +92,8 @@ that is actually referenced.
|
|||
@specspecsubform[#:literals (except-out)
|
||||
(except-out provide-spec id ...)]{
|
||||
|
||||
Like @scheme[provide-spec], but omitting the export of each
|
||||
@scheme[id], where @scheme[id] is the external name of the binding to
|
||||
Like @racket[provide-spec], but omitting the export of each
|
||||
@racket[id], where @racket[id] is the external name of the binding to
|
||||
omit.
|
||||
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ omit.
|
|||
@specspecsubform[#:literals (prefix-out)
|
||||
(prefix-out prefix-id provide-spec)]{
|
||||
|
||||
Like @scheme[provide-spec], but adding @scheme[prefix-id] to the
|
||||
Like @racket[provide-spec], but adding @racket[prefix-id] to the
|
||||
beginning of the external name for each exported binding.
|
||||
|
||||
}
|
||||
|
|
|
@ -3,44 +3,44 @@
|
|||
scribble/eval
|
||||
"guide-utils.ss")
|
||||
|
||||
@title[#:tag "module-require"]{Imports: @scheme[require]}
|
||||
@title[#:tag "module-require"]{Imports: @racket[require]}
|
||||
|
||||
The @scheme[require] form imports from another module. A
|
||||
@scheme[require] form can appear within a module, in which case it
|
||||
The @racket[require] form imports from another module. A
|
||||
@racket[require] form can appear within a module, in which case it
|
||||
introduces bindings from the specified module into importing module. A
|
||||
@scheme[require] form can also appear at the top level, in which case
|
||||
@racket[require] form can also appear at the top level, in which case
|
||||
it both imports bindings and @deftech{instantiates} the specified
|
||||
module; that is, it evaluates the body definitions and expressions of
|
||||
the specified module, if they have not been evaluated already.
|
||||
|
||||
A single @scheme[require] can specify multiple imports at once:
|
||||
A single @racket[require] can specify multiple imports at once:
|
||||
|
||||
@specform[(require require-spec ...)]{}
|
||||
|
||||
Specifying multiple @scheme[_require-spec]s in a single
|
||||
@scheme[require] is essentially the same as using multiple
|
||||
@scheme[require]s, each with a single @scheme[_require-spec]. The
|
||||
Specifying multiple @racket[_require-spec]s in a single
|
||||
@racket[require] is essentially the same as using multiple
|
||||
@racket[require]s, each with a single @racket[_require-spec]. The
|
||||
difference is minor, and confined to the top-level: a single
|
||||
@scheme[require] can import a given identifier at most once, whereas a
|
||||
separate @scheme[require] can replace the bindings of a previous
|
||||
@scheme[require] (both only at the top level, outside of a module).
|
||||
@racket[require] can import a given identifier at most once, whereas a
|
||||
separate @racket[require] can replace the bindings of a previous
|
||||
@racket[require] (both only at the top level, outside of a module).
|
||||
|
||||
The allowed shape of a @scheme[_require-spec] is defined recursively:
|
||||
The allowed shape of a @racket[_require-spec] is defined recursively:
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@specspecsubform[module-path]{
|
||||
|
||||
In its simplest form, a @scheme[_require-spec] is a
|
||||
@scheme[module-path] (as defined in the previous section,
|
||||
In its simplest form, a @racket[_require-spec] is a
|
||||
@racket[module-path] (as defined in the previous section,
|
||||
@secref["module-paths"]). In this case, the bindings introduced
|
||||
by @scheme[require] are determined by @scheme[provide] declarations
|
||||
within each module referenced by each @scheme[module-path].
|
||||
by @racket[require] are determined by @racket[provide] declarations
|
||||
within each module referenced by each @racket[module-path].
|
||||
|
||||
@examples[
|
||||
(module m scheme
|
||||
(module m racket
|
||||
(provide color)
|
||||
(define color "blue"))
|
||||
(module n scheme
|
||||
(module n racket
|
||||
(provide size)
|
||||
(define size 17))
|
||||
(require 'm 'n)
|
||||
|
@ -55,15 +55,15 @@ within each module referenced by each @scheme[module-path].
|
|||
([id-maybe-renamed id
|
||||
[orig-id bind-id]])]{
|
||||
|
||||
An @scheme[only-in] form limits the set of bindings that would be introduced
|
||||
by a base @scheme[require-spec]. Also, @scheme[only-in] optionally
|
||||
renames each binding that is preserved: in a @scheme[[orig-id
|
||||
bind-id]] form, the @scheme[orig-id] refers to a binding implied by
|
||||
@scheme[require-spec], and @scheme[bind-id] is the name that will be
|
||||
bound in the importing context instead of @scheme[bind-id].
|
||||
An @racket[only-in] form limits the set of bindings that would be introduced
|
||||
by a base @racket[require-spec]. Also, @racket[only-in] optionally
|
||||
renames each binding that is preserved: in a @racket[[orig-id
|
||||
bind-id]] form, the @racket[orig-id] refers to a binding implied by
|
||||
@racket[require-spec], and @racket[bind-id] is the name that will be
|
||||
bound in the importing context instead of @racket[bind-id].
|
||||
|
||||
@examples[
|
||||
(module m (lib "scheme")
|
||||
(module m (lib "racket")
|
||||
(provide tastes-great?
|
||||
less-filling?)
|
||||
(define tastes-great? #t)
|
||||
|
@ -79,8 +79,8 @@ less-filling?
|
|||
@specspecsubform[#:literals (except-in)
|
||||
(except-in require-spec id ...)]{
|
||||
|
||||
This form is the complement of @scheme[only]: it excludes specific
|
||||
bindings from the set specified by @scheme[require-spec].
|
||||
This form is the complement of @racket[only]: it excludes specific
|
||||
bindings from the set specified by @racket[require-spec].
|
||||
|
||||
}
|
||||
|
||||
|
@ -88,31 +88,31 @@ bindings from the set specified by @scheme[require-spec].
|
|||
@specspecsubform[#:literals (rename-in)
|
||||
(rename-in require-spec [orig-id bind-id] ...)]{
|
||||
|
||||
This form supports renaming like @scheme[only-in], but leaving alone
|
||||
identifiers from @scheme[require-spec] that are not mentioned as an
|
||||
@scheme[orig-id]. }
|
||||
This form supports renaming like @racket[only-in], but leaving alone
|
||||
identifiers from @racket[require-spec] that are not mentioned as an
|
||||
@racket[orig-id]. }
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@specspecsubform[#:literals (prefix-in)
|
||||
(prefix-in prefix-id require-spec)]{
|
||||
|
||||
This is a shorthand for renaming, where @scheme[prefix-id] is added to
|
||||
the front of each identifier specified by @scheme[require-spec].
|
||||
This is a shorthand for renaming, where @racket[prefix-id] is added to
|
||||
the front of each identifier specified by @racket[require-spec].
|
||||
|
||||
}
|
||||
|
||||
The @scheme[only-in], @scheme[except-in], @scheme[rename-in], and
|
||||
@scheme[prefix-in] forms can be nested to implement more complex
|
||||
The @racket[only-in], @racket[except-in], @racket[rename-in], and
|
||||
@racket[prefix-in] forms can be nested to implement more complex
|
||||
manipulations of imported bindings. For example,
|
||||
|
||||
@schemeblock[(require (prefix-in m: (except-in 'm ghost)))]
|
||||
@racketblock[(require (prefix-in m: (except-in 'm ghost)))]
|
||||
|
||||
imports all bindings that @scheme[m]
|
||||
exports, except for the @scheme[ghost] binding, and with local names
|
||||
that are prefixed with @scheme[m:].
|
||||
imports all bindings that @racket[m]
|
||||
exports, except for the @racket[ghost] binding, and with local names
|
||||
that are prefixed with @racket[m:].
|
||||
|
||||
Equivalently, the @scheme[prefix-in] could be applied before
|
||||
@scheme[except-in], as long as the omission with @scheme[except-in] is
|
||||
specified using the @scheme[m:] prefix:
|
||||
Equivalently, the @racket[prefix-in] could be applied before
|
||||
@racket[except-in], as long as the omission with @racket[except-in] is
|
||||
specified using the @racket[m:] prefix:
|
||||
|
||||
@schemeblock[(require (except-in (prefix m: 'm) m:ghost))]
|
||||
@racketblock[(require (except-in (prefix m: 'm) m:ghost))]
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
|
||||
@title[#:tag "module-set"]{Assignment and Redefinition}
|
||||
|
||||
The use of @scheme[set!] on variables defined within a module is
|
||||
The use of @racket[set!] on variables defined within a module is
|
||||
limited to the body of the defining module. That is, a module is
|
||||
allowed to change the value of its own definitions, and such changes
|
||||
are visible to importing modules. However, an importing context is not
|
||||
allowed to change the value of an imported binding.
|
||||
|
||||
@examples[
|
||||
(module m scheme
|
||||
(module m racket
|
||||
(provide counter increment!)
|
||||
(define counter 0)
|
||||
(define (increment!)
|
||||
|
@ -26,26 +26,26 @@ allowed to change the value of an imported binding.
|
|||
|
||||
As the above example illustrates, a module can always grant others the
|
||||
ability to change its exports by providing a mutator function, such as
|
||||
@scheme[increment!].
|
||||
@racket[increment!].
|
||||
|
||||
The prohibition on assignment of imported variables helps support
|
||||
modular reasoning about programs. For example, in the module,
|
||||
|
||||
@schemeblock[
|
||||
(module m scheme
|
||||
@racketblock[
|
||||
(module m racket
|
||||
(provide rx:fish fishy-string?)
|
||||
(define rx:fish #rx"fish")
|
||||
(define (fishy-string? s)
|
||||
(regexp-match? s rx:fish)))
|
||||
]
|
||||
|
||||
the function @scheme[fishy-string?] will always match strings that
|
||||
contain ``fish'', no matter how other modules use the @scheme[rx:fish]
|
||||
the function @racket[fishy-string?] will always match strings that
|
||||
contain ``fish'', no matter how other modules use the @racket[rx:fish]
|
||||
binding. For essentially the same reason that it helps programmers,
|
||||
the prohibition on assignment to imports also allows many programs to
|
||||
be executed more efficiently.
|
||||
|
||||
Along the same lines, when a module contains no @scheme[set!] of a
|
||||
Along the same lines, when a module contains no @racket[set!] of a
|
||||
particular identifier that is defined within the module, then the
|
||||
identifier is considered a @defterm{constant} that cannot be
|
||||
changed---not even by re-declaring the module.
|
||||
|
@ -54,30 +54,30 @@ Consequently, re-declaration of a module is not generally allowed.
|
|||
For file-based modules, simply changing the file does not lead to a
|
||||
re-declaration in any case, because file-based modules are loaded on
|
||||
demand, and the previously loaded declarations satisfy future
|
||||
requests. It is possible to use Scheme's reflection support to
|
||||
requests. It is possible to use Racket's reflection support to
|
||||
re-declare a module, however, and non-file modules can be re-declared
|
||||
in the @tech{REPL}; in such cases, the re-declaration may fail if it
|
||||
involves the re-definition of a previously constant binding.
|
||||
|
||||
@interaction[
|
||||
(module m scheme
|
||||
(module m racket
|
||||
(define pie 3.141597))
|
||||
(require 'm)
|
||||
(module m scheme
|
||||
(module m racket
|
||||
(define pie 3))
|
||||
]
|
||||
|
||||
For exploration and debugging purposes, the Scheme reflective layer
|
||||
provides a @scheme[compile-enforce-module-constants] parameter
|
||||
For exploration and debugging purposes, the Racket reflective layer
|
||||
provides a @racket[compile-enforce-module-constants] parameter
|
||||
to disable the enforcement of constants.
|
||||
|
||||
@interaction[
|
||||
(compile-enforce-module-constants #f)
|
||||
(module m2 scheme
|
||||
(module m2 racket
|
||||
(provide pie)
|
||||
(define pie 3.141597))
|
||||
(require 'm2)
|
||||
(module m2 scheme
|
||||
(module m2 racket
|
||||
(provide pie)
|
||||
(define pie 3))
|
||||
(compile-enforce-module-constants #t)
|
||||
|
|
|
@ -8,14 +8,14 @@
|
|||
@title{Module Syntax}
|
||||
|
||||
The @litchar{#lang} at the start of a module file begins a shorthand
|
||||
for a @scheme[module] form, much like @litchar{'} is a shorthand for a
|
||||
@scheme[quote] form. Unlike @litchar{'}, the @litchar{#lang}
|
||||
for a @racket[module] form, much like @litchar{'} is a shorthand for a
|
||||
@racket[quote] form. Unlike @litchar{'}, the @litchar{#lang}
|
||||
shorthand does not work well in a @tech{REPL}, in part because it must be
|
||||
terminated by an end-of-file, but also because the longhand expansion
|
||||
of @litchar{#lang} depends on the name of the enclosing file.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "module-syntax"]{The @scheme[module] Form}
|
||||
@section[#:tag "module-syntax"]{The @racket[module] Form}
|
||||
|
||||
The longhand form of a module declaration, which works in a
|
||||
@tech{REPL} as well as a file, is
|
||||
|
@ -25,29 +25,29 @@ The longhand form of a module declaration, which works in a
|
|||
decl ...)
|
||||
]
|
||||
|
||||
where the @scheme[_name-id] is a name for the module,
|
||||
@scheme[_initial-module-path] is an initial import, and each
|
||||
@scheme[_decl] is an import, export, definition, or expression. In
|
||||
the case of a file, @scheme[_name-id] must match the name of the
|
||||
where the @racket[_name-id] is a name for the module,
|
||||
@racket[_initial-module-path] is an initial import, and each
|
||||
@racket[_decl] is an import, export, definition, or expression. In
|
||||
the case of a file, @racket[_name-id] must match the name of the
|
||||
containing file, minus its directory path or file extension.
|
||||
|
||||
The @scheme[_initial-module-path] is needed because even the
|
||||
@scheme[require] form must be imported for further use in the module
|
||||
body. In other words, the @scheme[_initial-module-path] import
|
||||
The @racket[_initial-module-path] is needed because even the
|
||||
@racket[require] form must be imported for further use in the module
|
||||
body. In other words, the @racket[_initial-module-path] import
|
||||
bootstraps the syntax available in the body. The most commonly used
|
||||
@scheme[_initial-module-path] is @scheme[scheme], which supplies most
|
||||
of the bindings described in this guide, including @scheme[require],
|
||||
@scheme[define], and @scheme[provide]. Another commonly used
|
||||
@scheme[_initial-module-path] is @scheme[scheme/base], which provides
|
||||
@racket[_initial-module-path] is @racketmodname[racket], which supplies most
|
||||
of the bindings described in this guide, including @racket[require],
|
||||
@racket[define], and @racket[provide]. Another commonly used
|
||||
@racket[_initial-module-path] is @racketmodname[racket/base], which provides
|
||||
less functionality, but still much of the most commonly needed
|
||||
functions and syntax.
|
||||
|
||||
For example, the @filepath{cake.ss} example of the
|
||||
For example, the @filepath{cake.rkt} example of the
|
||||
@seclink["module-basics"]{previous section} could be written as
|
||||
|
||||
@schemeblock+eval[
|
||||
@racketblock+eval[
|
||||
#:eval cake-eval
|
||||
(module cake scheme
|
||||
(module cake racket
|
||||
(provide print-cake)
|
||||
|
||||
(define (print-cake n)
|
||||
|
@ -57,8 +57,8 @@ For example, the @filepath{cake.ss} example of the
|
|||
(printf "---~a---\n" (make-string n #\-))))
|
||||
]
|
||||
|
||||
Furthermore, this @scheme[module] form can be evaluated in a
|
||||
@tech{REPL} to declare a @scheme[cake] module that is not associated
|
||||
Furthermore, this @racket[module] form can be evaluated in a
|
||||
@tech{REPL} to declare a @racket[cake] module that is not associated
|
||||
with any file. To refer to such an unassociated module, quote the
|
||||
module name:
|
||||
|
||||
|
@ -70,53 +70,53 @@ module name:
|
|||
|
||||
Declaring a module does not immediately evaluate the body definitions
|
||||
and expressions of the module. The module must be explicitly
|
||||
@scheme[require]d at the top level to trigger evaluation. After
|
||||
evaluation is triggered once, later @scheme[require]s do not
|
||||
@racket[require]d at the top level to trigger evaluation. After
|
||||
evaluation is triggered once, later @racket[require]s do not
|
||||
re-evaluate the module body.
|
||||
|
||||
@examples[
|
||||
(module hi scheme
|
||||
(module hi racket
|
||||
(printf "Hello\n"))
|
||||
(require 'hi)
|
||||
(require 'hi)
|
||||
]
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "hash-lang"]{The @schememodfont{#lang} Shorthand}
|
||||
@section[#:tag "hash-lang"]{The @racketmodfont{#lang} Shorthand}
|
||||
|
||||
The body of a @schememodfont{#lang} shorthand has no specific syntax,
|
||||
The body of a @racketmodfont{#lang} shorthand has no specific syntax,
|
||||
because the syntax is determined by the language name that follows
|
||||
@schememodfont{#lang}.
|
||||
@racketmodfont{#lang}.
|
||||
|
||||
In the case of @schememodfont{#lang} @schememodname[scheme], the syntax
|
||||
In the case of @racketmodfont{#lang} @racketmodname[racket], the syntax
|
||||
is
|
||||
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
_decl ...]
|
||||
|
||||
which reads the same as
|
||||
|
||||
@schemeblock[
|
||||
(module _name scheme
|
||||
@racketblock[
|
||||
(module _name racket
|
||||
_decl ...)
|
||||
]
|
||||
|
||||
where @scheme[_name] is derived from the name of the file that
|
||||
contains the @schememodfont{#lang} form.
|
||||
where @racket[_name] is derived from the name of the file that
|
||||
contains the @racketmodfont{#lang} form.
|
||||
|
||||
The @schememodfont{#lang} @scheme[scheme/base] form has the same
|
||||
syntax as @schememodfont{#lang} @schememodname[scheme], except that
|
||||
the longhand expansion uses @scheme[scheme/base] instead of
|
||||
@scheme[scheme]. The @schememodfont{#lang} @scheme[honu] form, in
|
||||
The @racketmodfont{#lang} @racketmodname[racket/base] form has the same
|
||||
syntax as @racketmodfont{#lang} @racketmodname[racket], except that
|
||||
the longhand expansion uses @racketmodname[racket/base] instead of
|
||||
@racketmodname[racket]. The @racketmodfont{#lang} @racket[honu] form, in
|
||||
contrast, has a completely different syntax that doesn't even look
|
||||
like Scheme, and which we do not attempt to describe in this guide.
|
||||
like Racket, and which we do not attempt to describe in this guide.
|
||||
|
||||
Unless otherwise specified, a module that is documented as a
|
||||
``language'' using the @schememodfont{#lang} notation will expand to
|
||||
@scheme[module] in the same way as @schememodfont{#lang}
|
||||
@schememodname[scheme]. The documented language name can be used
|
||||
directly with @scheme[module] or @scheme[require], too.
|
||||
``language'' using the @racketmodfont{#lang} notation will expand to
|
||||
@racket[module] in the same way as @racketmodfont{#lang}
|
||||
@racketmodname[racket]. The documented language name can be used
|
||||
directly with @racket[module] or @racket[require], too.
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
@title[#:tag "modules" #:style 'toc]{Modules}
|
||||
|
||||
|
||||
Modules let you organize Scheme code into multiple files and reusable
|
||||
Modules let you organize Racket code into multiple files and reusable
|
||||
libraries.
|
||||
|
||||
@local-table-of-contents[]
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
@title[#:tag "numbers"]{Numbers}
|
||||
|
||||
A Scheme @deftech{number} is either exact or inexact:
|
||||
A Racket @deftech{number} is either exact or inexact:
|
||||
|
||||
@itemize[
|
||||
|
||||
|
@ -13,16 +13,16 @@ A Scheme @deftech{number} is either exact or inexact:
|
|||
|
||||
@itemize[
|
||||
|
||||
@item{an arbitrarily large or small integer, such as @scheme[5],
|
||||
@scheme[99999999999999999], or @scheme[-17];}
|
||||
@item{an arbitrarily large or small integer, such as @racket[5],
|
||||
@racket[99999999999999999], or @racket[-17];}
|
||||
|
||||
@item{a rational that is exactly the ratio of two arbitrarily
|
||||
small or large integers, such as @scheme[1/2],
|
||||
@scheme[99999999999999999/2], or @scheme[-3/4]; or}
|
||||
small or large integers, such as @racket[1/2],
|
||||
@racket[99999999999999999/2], or @racket[-3/4]; or}
|
||||
|
||||
@item{a complex number with exact real and imaginary parts
|
||||
(where the imaginary part is not zero), such as @scheme[1+2i] or
|
||||
@scheme[1/2+3/4i].}
|
||||
(where the imaginary part is not zero), such as @racket[1+2i] or
|
||||
@racket[1/2+3/4i].}
|
||||
|
||||
]}
|
||||
|
||||
|
@ -31,14 +31,14 @@ A Scheme @deftech{number} is either exact or inexact:
|
|||
@itemize[
|
||||
|
||||
@item{an IEEE floating-point representation of a number, such
|
||||
as @scheme[2.0] or @scheme[3.14e87], where the IEEE
|
||||
as @racket[2.0] or @racket[3.14e87], where the IEEE
|
||||
infinities and not-a-number are written
|
||||
@scheme[+inf.0], @scheme[-inf.0], and @scheme[+nan.0]
|
||||
(or @schemevalfont{-nan.0}); or}
|
||||
@racket[+inf.0], @racket[-inf.0], and @racket[+nan.0]
|
||||
(or @racketvalfont{-nan.0}); or}
|
||||
|
||||
@item{a complex number with real and imaginary parts that are
|
||||
IEEE floating-point representations, such as
|
||||
@scheme[2.0+3.0i] or @scheme[-inf.0+nan.0i]; as a
|
||||
@racket[2.0+3.0i] or @racket[-inf.0+nan.0i]; as a
|
||||
special case, an inexact complex number can have an
|
||||
exact zero real part with an inexact imaginary part.}
|
||||
|
||||
|
@ -57,16 +57,16 @@ interpretation of digits.
|
|||
|
||||
@examples[
|
||||
0.5
|
||||
(eval:alts @#,schemevalfont{#e0.5} 1/2)
|
||||
(eval:alts @#,schemevalfont{#x03BB} #x03BB)
|
||||
(eval:alts @#,racketvalfont{#e0.5} 1/2)
|
||||
(eval:alts @#,racketvalfont{#x03BB} #x03BB)
|
||||
]
|
||||
|
||||
Computations that involve an inexact number produce inexact results,
|
||||
so that inexactness acts as a kind of taint on numbers. Beware,
|
||||
however, that Scheme offers no ``inexact booleans'', so computations
|
||||
however, that Racket offers no ``inexact booleans,'' so computations
|
||||
that branch on the comparison of inexact numbers can nevertheless
|
||||
produce exact results. The procedures @scheme[exact->inexact] and
|
||||
@scheme[inexact->exact] convert between the two
|
||||
produce exact results. The procedures @racket[exact->inexact] and
|
||||
@racket[inexact->exact] convert between the two
|
||||
types of numbers.
|
||||
|
||||
@examples[
|
||||
|
@ -76,9 +76,9 @@ types of numbers.
|
|||
(inexact->exact 0.1)
|
||||
]
|
||||
|
||||
Inexact results are also produced by procedures such as @scheme[sqrt],
|
||||
@scheme[log], and @scheme[sin] when an exact result would require
|
||||
representing real numbers that are not rational. Scheme can represent
|
||||
Inexact results are also produced by procedures such as @racket[sqrt],
|
||||
@racket[log], and @racket[sin] when an exact result would require
|
||||
representing real numbers that are not rational. Racket can represent
|
||||
only rational numbers and complex numbers with rational parts.
|
||||
|
||||
@examples[
|
||||
|
@ -105,9 +105,9 @@ with inexact numbers.
|
|||
|
||||
The number categories @deftech{integer}, @deftech{rational},
|
||||
@deftech{real} (always rational), and @deftech{complex} are defined in
|
||||
the usual way, and are recognized by the procedures @scheme[integer?],
|
||||
@scheme[rational?], @scheme[real?], and @scheme[complex?], in addition
|
||||
to the generic @scheme[number?]. A few mathematical procedures accept
|
||||
the usual way, and are recognized by the procedures @racket[integer?],
|
||||
@racket[rational?], @racket[real?], and @racket[complex?], in addition
|
||||
to the generic @racket[number?]. A few mathematical procedures accept
|
||||
only real numbers, but most implement standard extensions to complex
|
||||
numbers.
|
||||
|
||||
|
@ -123,10 +123,10 @@ numbers.
|
|||
(sin -5+2i)
|
||||
]
|
||||
|
||||
The @scheme[=] procedure compares numbers for numerical equality. If
|
||||
The @racket[=] procedure compares numbers for numerical equality. If
|
||||
it is given both inexact and exact numbers to compare, it essentially
|
||||
converts the inexact numbers to exact before comparing. The
|
||||
@scheme[eqv?] (and therefore @scheme[equal?]) procedure, in contrast,
|
||||
@racket[eqv?] (and therefore @racket[equal?]) procedure, in contrast,
|
||||
compares numbers considering both exactness and numerical equality.
|
||||
|
||||
@examples[
|
||||
|
@ -137,8 +137,8 @@ compares numbers considering both exactness and numerical equality.
|
|||
Beware of comparisons involving inexact numbers, which by their nature
|
||||
can have surprising behavior. Even apparently simple inexact numbers
|
||||
may not mean what you think they mean; for example, while a base-2
|
||||
IEEE floating-point number can represent @scheme[1/2] exactly, it
|
||||
can only approximate @scheme[1/10]:
|
||||
IEEE floating-point number can represent @racket[1/2] exactly, it
|
||||
can only approximate @racket[1/10]:
|
||||
|
||||
@examples[
|
||||
(= 1/2 0.5)
|
||||
|
|
|
@ -11,7 +11,8 @@ procedures extract the first and second elements of the pair,
|
|||
respectively. The @scheme[pair?] predicate recognizes pairs.
|
||||
|
||||
Some pairs print by wrapping parentheses around the printed forms of
|
||||
the two pair elements, putting a @litchar{.} between them.
|
||||
the two pair elements, putting a @litchar{`} at the beginning and a
|
||||
@litchar{.} between the elements.
|
||||
|
||||
@examples[
|
||||
(cons 1 2)
|
||||
|
@ -27,8 +28,8 @@ or it is a pair whose first element is a list element and whose second
|
|||
element is a list. The @scheme[list?] predicate recognizes lists. The
|
||||
@scheme[null?] predicate recognizes the empty list.
|
||||
|
||||
A list prints as a pair of parentheses wrapped around the list
|
||||
elements.
|
||||
A list prints as a @litchar{`} followed by a pair of parentheses
|
||||
wrapped around the list elements.
|
||||
|
||||
@examples[
|
||||
null
|
||||
|
@ -38,13 +39,13 @@ null
|
|||
(list? (cons 1 2))
|
||||
]
|
||||
|
||||
An expression with @litchar{'} followed by the printed form of a pair
|
||||
or list produces a pair or list constant.
|
||||
The @scheme[display] function prints a pair or list without a leading
|
||||
@litchar{`}:
|
||||
|
||||
@examples[
|
||||
'()
|
||||
'(1 . 2)
|
||||
'(1 2 3)
|
||||
(display (cons 1 2))
|
||||
(display null)
|
||||
(display (list 1 2 3))
|
||||
]
|
||||
|
||||
Pairs are immutable (contrary to Lisp tradition), and @scheme[pair?]
|
||||
|
|
|
@ -4,140 +4,160 @@
|
|||
"guide-utils.ss"
|
||||
(for-label (only-in mzscheme fluid-let)))
|
||||
|
||||
@title[#:tag "parameterize"]{Dynamic Binding: @scheme[parameterize]}
|
||||
@(define param-eval (make-base-eval))
|
||||
|
||||
@scheme[parameterize] is used to have values that are ``dynamically scoped''.
|
||||
You get a parameter with @scheme[make-parameter]. The parameter itself
|
||||
behaves as a function: call it with no inputs and you get its value,
|
||||
call it with one value and it will set the value. The settings that are
|
||||
adjusted by a @scheme[parameterize] form are called @deftech{parameters}.
|
||||
For example:
|
||||
@title[#:tag "parameterize"]{Dynamic Binding: @racket[parameterize]}
|
||||
|
||||
@margin-note{The term ``parameter'' is sometimes used to refer to the
|
||||
arguments of a function, but ``parameter'' in PLT Scheme
|
||||
has the more specific meaning described here.}
|
||||
@refalso["parameters"]{@racket[parameterize]}
|
||||
|
||||
|
||||
@examples[
|
||||
(define p (make-parameter "blah"))
|
||||
(p)
|
||||
(p "meh")
|
||||
(p)]
|
||||
|
||||
Many functions (including many primitive ones) use parameters as a way
|
||||
to customize their behavior. For example @scheme[printf] will print text
|
||||
using the port that is the value of the @scheme[current-output-port]
|
||||
parameter. Now, say that you have some function that prints
|
||||
something:
|
||||
|
||||
@examples[
|
||||
(define (foo x) (printf "the value of x is ~s\n"))
|
||||
]
|
||||
|
||||
You usually call this function and see something printed on the screen
|
||||
-- but in some cases you want to use it to print something to a file
|
||||
or whatever. You could do this:
|
||||
|
||||
@examples[
|
||||
(define (bar)
|
||||
(let ([old-stdout (current-output-port)])
|
||||
(current-output-port my-own-port)
|
||||
(foo some-value)
|
||||
(current-output-port old-stdout)))
|
||||
]
|
||||
|
||||
One problem with this is that it is tedious to do -- but that's easily
|
||||
solved with a macro. (In fact, PLT still has a construct that does
|
||||
that in some languages: @scheme[fluid-let].) But there are more problems
|
||||
here: what happens if the call to @scheme[foo] results in a runtime error?
|
||||
This might leave the system in a bad state, where all output goes to
|
||||
your port (and you won't even see a problem, since it won't print
|
||||
anything). A solution for that (which @scheme[fluid-let] uses too) is to
|
||||
protect the saving/restoring of the parameter with @scheme[dynamic-wind],
|
||||
which makes sure that if there's an error (and more, if you know about
|
||||
continuations) then the value is still restored.
|
||||
|
||||
So the question is what's the point of having parameters instead of
|
||||
just using globals and @scheme[fluid-let]? There are two more problems that
|
||||
you cannot solve with just globals. One is what happens when you have
|
||||
multiple threads -- in this case, setting the value temporarily will
|
||||
affect other threads, which may still want to print to the standard
|
||||
output. Parameters solve this by having a specific value per-thread.
|
||||
What happens is that each thread ``inherits'' the value from the thread
|
||||
that created it, and changes in one thread are visible only in that
|
||||
thread.
|
||||
|
||||
The other problem is more subtle. Say that you have a parameter with
|
||||
a numeric value, and you want to do the following:
|
||||
|
||||
@examples[
|
||||
(define (foo)
|
||||
(parameterize ([p 'any-expression-goes-here])
|
||||
(foo)))
|
||||
]
|
||||
|
||||
In Scheme, ``tail calls'' are important -- they are the basic tool for
|
||||
creating loops and much more. @scheme[parameterize] does some magic that
|
||||
allows it to change the parameter value temporarily but still preserve
|
||||
these tail calls. For example, in the above case, you @bold{will} get an
|
||||
infinite loop, rather than get a stack overflow error -- what happens
|
||||
is that each of these @scheme[parameterize] expressions can somehow detect
|
||||
when there's an earlier @scheme[parameterize] that no longer needs to do its
|
||||
cleanup.
|
||||
|
||||
Finally, @scheme[parameterize] actually uses two important parts of PLT to do
|
||||
its job: it uses thread cells to implement per-thread values, and it
|
||||
uses continuation marks to be able to preserve tail-calls. Each of
|
||||
these features is useful in itself.
|
||||
The @racket[parameterize] form associates a new value with a
|
||||
@deftech{parameter} during the evaluation of @racket[_body]
|
||||
expressions:
|
||||
|
||||
@specform[(parameterize ([parameter-expr value-expr] ...)
|
||||
body ...+)]
|
||||
|
||||
The result of a @scheme[parameterize] form is the result of the last
|
||||
@scheme[_body] expression. While the @scheme[_body] expressions are
|
||||
evaluated, the parameter produced by each @scheme[_parameter-expr] is
|
||||
set to the result of the corresponding @scheme[_value-expr].
|
||||
@margin-note{The term ``parameter'' is sometimes used to refer to the
|
||||
arguments of a function, but ``parameter'' in Racket
|
||||
has the more specific meaning described here.}
|
||||
|
||||
Many parameters are built in. For example, the
|
||||
@scheme[error-print-width] parameter controls how many characters of a
|
||||
value are printed in an error message (in case the printed form of the
|
||||
value is very large):
|
||||
For example, the @racket[error-print-width] parameter controls how
|
||||
many characters of a value are printed in an error message:
|
||||
|
||||
@interaction[
|
||||
(parameterize ([error-print-width 10])
|
||||
(parameterize ([error-print-width 5])
|
||||
(car (expt 10 1024)))
|
||||
(parameterize ([error-print-width 5])
|
||||
(parameterize ([error-print-width 10])
|
||||
(car (expt 10 1024)))
|
||||
]
|
||||
|
||||
The @scheme[error-print-width] parameter acts like a kind of default
|
||||
argument to the function that formats error messages. This
|
||||
parameter-based argument can be configured far from the actual call to
|
||||
the error-formatting function, which in this case is called deep
|
||||
within the implementation of @scheme[car].
|
||||
|
||||
The @scheme[parameterize] form adjusts the value of a parameter only
|
||||
while evaluating its body expressions. After the body produces a
|
||||
value, the parameter reverts to its previous value. If control escapes
|
||||
from the body due to an exception, as in the above example, then the
|
||||
parameter value is restored in that case, too. Finally, parameter
|
||||
values are thread-specific, so that multiple threads do not interfere
|
||||
with each others' settings.
|
||||
|
||||
Use @scheme[make-parameter] to create a new parameter that works with
|
||||
@scheme[parameterize]. The argument to @scheme[make-parameter] is the
|
||||
value of the parameter when it is not otherwise set by
|
||||
@scheme[parameterize]. To access the current value of the parameter,
|
||||
call it like a function.
|
||||
More generally, parameters implement a kind of dynamic binding. The
|
||||
@racket[make-parameter] function takes any value and returns a new
|
||||
parameter that is initialized to the given value. Applying the
|
||||
parameter as a function returns its current value:
|
||||
|
||||
@interaction[
|
||||
(define favorite-flavor (make-parameter 'chocolate))
|
||||
(favorite-flavor)
|
||||
(define (scoop)
|
||||
`(scoop of ,(favorite-flavor)))
|
||||
(define (ice-cream n)
|
||||
(list (scoop) (scoop) (scoop)))
|
||||
(parameterize ([favorite-flavor 'strawberry])
|
||||
(ice-cream 3))
|
||||
(ice-cream 3)
|
||||
#:eval param-eval
|
||||
(define location (make-parameter "here"))
|
||||
(location)
|
||||
]
|
||||
|
||||
In a @scheme[parameterize] form, each @racket[_parameter-expr] must
|
||||
produce a parameter. During the evaluation of the @scheme[body]s, each
|
||||
specified parameter is given the result of the corresponding
|
||||
@scheme[_value-expr]. When control leaves the @racket[parameterize]
|
||||
form---either through a normal return, an exception, or some other
|
||||
escape---the parameter reverts to its earlier value:
|
||||
|
||||
@interaction[
|
||||
#:eval param-eval
|
||||
(parameterize ([location "there"])
|
||||
(location))
|
||||
(location)
|
||||
(parameterize ([location "in a house"])
|
||||
(list (location)
|
||||
(parameterize ([location "with a mouse"])
|
||||
(location))
|
||||
(location)))
|
||||
(parameterize ([location "in a box"])
|
||||
(car (location)))
|
||||
(location)
|
||||
]
|
||||
|
||||
The @scheme[parameterize] form is not a binding form like
|
||||
@scheme[let]; each use of @racket[location] above refers directly to
|
||||
the original definition. A @scheme[parameterize] form adjusts the
|
||||
value of a parameter during the whole time that the
|
||||
@scheme[parameterize] body is evaluated, even for uses of the
|
||||
parameter that are textually outside of the @racket[parameterize]
|
||||
body:
|
||||
|
||||
@interaction[
|
||||
#:eval param-eval
|
||||
(define (would-you-could-you?)
|
||||
(and (not (equal? (location) "here"))
|
||||
(not (equal? (location) "there"))))
|
||||
|
||||
(would-you-could-you?)
|
||||
(parameterize ([location "on a bus"])
|
||||
(would-you-could-you?))
|
||||
]
|
||||
|
||||
If a use of a parameter is textually inside the body of a
|
||||
@racket[parameterize] but not evaluated before the
|
||||
@racket[parameterize] form produces a value, then the use does not see
|
||||
the value installed by the @racket[parameterize] form:
|
||||
|
||||
@interaction[
|
||||
#:eval param-eval
|
||||
(let ([get (parameterize ([location "with a fox"])
|
||||
(lambda () (location)))])
|
||||
(get))
|
||||
]
|
||||
|
||||
The current binding of a parameter can be adjusted imperatively by
|
||||
calling the parameter as a function with a value. If a
|
||||
@racket[parameterize] has adjusted the value of the parameter, then
|
||||
directly applying the parameter procedure affects only the value
|
||||
associated with the active @racket[parameterize]:
|
||||
|
||||
@interaction[
|
||||
#:eval param-eval
|
||||
(define (try-again! where)
|
||||
(location where))
|
||||
|
||||
(location)
|
||||
(parameterize ([location "on a train"])
|
||||
(list (location)
|
||||
(begin (try-again! "in a boat")
|
||||
(location))))
|
||||
(location)
|
||||
]
|
||||
|
||||
Using @racket[parameterize] is generally preferable to updating a
|
||||
parameter value imperatively---for much the same reasons that binding
|
||||
a fresh variable with @scheme[let] is preferable to using
|
||||
@scheme[set!] (see @secref["set!"]).
|
||||
|
||||
It may seem that variables and @racket[set!] can solve many of the
|
||||
same problems that parameters solve. For example, @racket[lokation]
|
||||
could be defined as a string, and @racket[set!] could be used
|
||||
to adjust its value:
|
||||
|
||||
@interaction[
|
||||
#:eval param-eval
|
||||
(define lokation "here")
|
||||
|
||||
(define (would-ya-could-ya?)
|
||||
(and (not (equal? lokation "here"))
|
||||
(not (equal? lokation "there"))))
|
||||
|
||||
(set! location "on a bus")
|
||||
(would-ya-could-ya?)
|
||||
]
|
||||
|
||||
Parameters, however, offer several crucial advantages over
|
||||
@scheme[set!]:
|
||||
|
||||
@itemlist[
|
||||
|
||||
@item{The @racket[parameterize] form helps automatically reset the
|
||||
value of a parameter when control escapes due to an exception.
|
||||
Adding exception handlers and other forms to rewind a
|
||||
@scheme[set!] is relatively tedious.}
|
||||
|
||||
@item{Parameters work nicely with tail calls (see
|
||||
@secref["tail-recursion"]). The last @racket[_body] in a
|
||||
@racket[parameterize] form is in @tech{tail position} with
|
||||
respect to the @racket[parameterize] form.}
|
||||
|
||||
@item{Parameters work properly with threads (see
|
||||
@refsecref["threads"]). The @scheme[parameterize] form adjusts
|
||||
the value of a parameter only for evaluation in the current
|
||||
thread, which avoids race conditions with other threads.}
|
||||
|
||||
]
|
||||
|
||||
@; ----------------------------------------
|
||||
|
||||
@close-eval[param-eval]
|
||||
|
|
|
@ -3,41 +3,43 @@
|
|||
scribble/eval
|
||||
"guide-utils.ss")
|
||||
|
||||
@(define qq (scheme quasiquote))
|
||||
@(define uq (scheme unquote))
|
||||
@(define qq (racket quasiquote))
|
||||
@(define uq (racket unquote))
|
||||
|
||||
@title{Quasiquoting: @scheme[quasiquote] and @schemevalfont{`}}
|
||||
@title[#:tag "qq"]{Quasiquoting: @racket[quasiquote] and @racketvalfont{`}}
|
||||
|
||||
The @scheme[quasiquote] form is similar to @scheme[quote]:
|
||||
@refalso["quasiquote"]{@racket[quasiquote]}
|
||||
|
||||
The @racket[quasiquote] form is similar to @racket[quote]:
|
||||
|
||||
@specform[(#,qq datum)]
|
||||
|
||||
However, for each @scheme[(#,uq _expr)]
|
||||
that appears within the @scheme[_datum], the @scheme[_expr] is
|
||||
However, for each @racket[(#,uq _expr)]
|
||||
that appears within the @racket[_datum], the @racket[_expr] is
|
||||
evaluated to produce a value that takes the place of the
|
||||
@scheme[unquote] sub-form.
|
||||
@racket[unquote] sub-form.
|
||||
|
||||
@examples[
|
||||
(eval:alts (#,qq (1 2 (#,uq (+ 1 2)) (#,uq (- 5 1))))
|
||||
`(1 2 ,(+ 1 2), (- 5 1)))
|
||||
]
|
||||
|
||||
The @scheme[unquote-splicing] form is similar to @scheme[unquote], but
|
||||
its @scheme[_expr] must produce a list, and the
|
||||
@scheme[unquote-splicing] form must appear in a context that produces
|
||||
The @racket[unquote-splicing] form is similar to @racket[unquote], but
|
||||
its @racket[_expr] must produce a list, and the
|
||||
@racket[unquote-splicing] form must appear in a context that produces
|
||||
either a list or a vector. As the name suggests, the resulting list
|
||||
is spliced into the context of its use.
|
||||
|
||||
@examples[
|
||||
(eval:alts (#,qq (1 2 (#,(scheme unquote-splicing) (list (+ 1 2) (- 5 1))) 5))
|
||||
(eval:alts (#,qq (1 2 (#,(racket unquote-splicing) (list (+ 1 2) (- 5 1))) 5))
|
||||
`(1 2 ,@(list (+ 1 2) (- 5 1)) 5))
|
||||
]
|
||||
|
||||
If a @scheme[quasiquote] form appears within an enclosing
|
||||
@scheme[quasiquote] form, then the inner @scheme[quasiquote]
|
||||
effectively cancels one layer of @scheme[unquote] and
|
||||
@scheme[unquote-splicing] forms, so that a second @scheme[unquote]
|
||||
or @scheme[unquote-splicing] is needed.
|
||||
If a @racket[quasiquote] form appears within an enclosing
|
||||
@racket[quasiquote] form, then the inner @racket[quasiquote]
|
||||
effectively cancels one layer of @racket[unquote] and
|
||||
@racket[unquote-splicing] forms, so that a second @racket[unquote]
|
||||
or @racket[unquote-splicing] is needed.
|
||||
|
||||
@examples[
|
||||
(eval:alts (#,qq (1 2 (#,qq (#,uq (+ 1 2)
|
||||
|
@ -48,7 +50,7 @@ or @scheme[unquote-splicing] is needed.
|
|||
]
|
||||
|
||||
The evaluation above will not actually print as shown. Instead, the
|
||||
shorthand form of @scheme[quasiquote] and @scheme[unquote] will be
|
||||
shorthand form of @racket[quasiquote] and @racket[unquote] will be
|
||||
used: @litchar{`} (i.e., a backquote) and @litchar{,} (i.e., a comma).
|
||||
The same shorthands can be used in expressions:
|
||||
|
||||
|
@ -56,7 +58,7 @@ The same shorthands can be used in expressions:
|
|||
`(1 2 `(,(+ 1 2) ,,(- 5 1)))
|
||||
]
|
||||
|
||||
The shorthand for of @scheme[unquote-splicing] is @litchar[",@"]:
|
||||
The shorthand for of @racket[unquote-splicing] is @litchar[",@"]:
|
||||
|
||||
@examples[
|
||||
`(1 2 ,@(list (+ 1 2) (- 5 1)))
|
||||
|
|
|
@ -3,63 +3,61 @@
|
|||
scribble/eval
|
||||
"guide-utils.ss")
|
||||
|
||||
@title[#:tag "quote"]{Quoting: @scheme[quote] and @schemevalfont{'}}
|
||||
@title[#:tag "quote"]{Quoting: @racket[quote] and @racketvalfont{'}}
|
||||
|
||||
@refalso["quote"]{@scheme[quote]}
|
||||
@refalso["quote"]{@racket[quote]}
|
||||
|
||||
The @scheme[quote] form produces a constant:
|
||||
The @racket[quote] form produces a constant:
|
||||
|
||||
@specform[(#,(schemekeywordfont "quote") datum)]
|
||||
@specform[(#,(racketkeywordfont "quote") datum)]
|
||||
|
||||
The syntax of a @scheme[datum] is technically specified as anything
|
||||
that the @scheme[read] function parses as a single element. The value
|
||||
of the @scheme[quote] form is the same value that @scheme[read] would
|
||||
produce given @scheme[_datum].
|
||||
The syntax of a @racket[datum] is technically specified as anything
|
||||
that the @racket[read] function parses as a single element. The value
|
||||
of the @racket[quote] form is the same value that @racket[read] would
|
||||
produce given @racket[_datum].
|
||||
|
||||
To a good approximation, the resulting value is such that
|
||||
@scheme[_datum] is the value's printed representation. Thus, it can be
|
||||
a symbol, a boolean, a number, a (character or byte) string, a
|
||||
character, a keyword, an empty list, a pair (or list) containing more
|
||||
such values, a vector containing more such values, a hash table
|
||||
containing more such values, or a box containing another such value.
|
||||
The @racket[_datum] can be a symbol, a boolean, a number, a (character
|
||||
or byte) string, a character, a keyword, an empty list, a pair (or
|
||||
list) containing more such values, a vector containing more such
|
||||
values, a hash table containing more such values, or a box containing
|
||||
another such value.
|
||||
|
||||
@examples[
|
||||
(eval:alts (#,(schemekeywordfont "quote") apple) 'apple)
|
||||
(eval:alts (#,(schemekeywordfont "quote") #t) #t)
|
||||
(eval:alts (#,(schemekeywordfont "quote") 42) 42)
|
||||
(eval:alts (#,(schemekeywordfont "quote") "hello") "hello")
|
||||
(eval:alts (#,(schemekeywordfont "quote") ()) '())
|
||||
(eval:alts (#,(schemekeywordfont "quote") ((1 2 3) #2("z" x) . the-end)) '((1 2 3) #2("z" x) . the-end))
|
||||
(eval:alts (#,(schemekeywordfont "quote") (1 2 #,(schemeparenfont ".") (3))) '(1 2 . (3)))
|
||||
(eval:alts (#,(racketkeywordfont "quote") apple) 'apple)
|
||||
(eval:alts (#,(racketkeywordfont "quote") #t) #t)
|
||||
(eval:alts (#,(racketkeywordfont "quote") 42) 42)
|
||||
(eval:alts (#,(racketkeywordfont "quote") "hello") "hello")
|
||||
(eval:alts (#,(racketkeywordfont "quote") ()) '())
|
||||
(eval:alts (#,(racketkeywordfont "quote") ((1 2 3) #2("z" x) . the-end)) '((1 2 3) #2("z" x) . the-end))
|
||||
(eval:alts (#,(racketkeywordfont "quote") (1 2 #,(racketparenfont ".") (3))) '(1 2 . (3)))
|
||||
]
|
||||
|
||||
As the last example above shows, the @scheme[_datum] does not have to
|
||||
be the normalized printed form of a value. A
|
||||
@scheme[_datum] cannot be a printed representation that starts with
|
||||
@litchar{#<}, however, so it cannot be @|void-const|,
|
||||
@|undefined-const|, or a procedure.
|
||||
As the last example above shows, the @racket[_datum] does not have to
|
||||
match the normalized printed form of a value. A @racket[_datum] cannot
|
||||
be a printed representation that starts with @litchar{#<}, so it
|
||||
cannot be @|void-const|, @|undefined-const|, or a procedure.
|
||||
|
||||
The @scheme[quote] form is rarely used for a @scheme[_datum] that is a
|
||||
The @racket[quote] form is rarely used for a @racket[_datum] that is a
|
||||
boolean, number, or string by itself, since the printed forms of those
|
||||
values can already be used as constants. The @scheme[quote] form is
|
||||
values can already be used as constants. The @racket[quote] form is
|
||||
more typically used for symbols and lists, which have other meanings
|
||||
(identifiers, function calls, etc.) when not quoted.
|
||||
|
||||
An expression
|
||||
|
||||
@specform[(quote @#,schemevarfont{datum})]
|
||||
@specform[(quote @#,racketvarfont{datum})]
|
||||
|
||||
is a shorthand for
|
||||
|
||||
@schemeblock[
|
||||
(#,(schemekeywordfont "quote") #,(scheme _datum))
|
||||
@racketblock[
|
||||
(#,(racketkeywordfont "quote") #,(racket _datum))
|
||||
]
|
||||
|
||||
and this shorthand is almost always used instead of
|
||||
@scheme[quote]. The shorthand applies even within the @scheme[_datum],
|
||||
so it can produce a list containing @scheme[quote].
|
||||
@racket[quote]. The shorthand applies even within the @racket[_datum],
|
||||
so it can produce a list containing @racket[quote].
|
||||
|
||||
@refdetails["parse-quote"]{the @schemevalfont{'} shorthand}
|
||||
@refdetails["parse-quote"]{the @racketvalfont{'} shorthand}
|
||||
|
||||
@examples[
|
||||
'apple
|
||||
|
|
|
@ -5,17 +5,17 @@
|
|||
|
||||
@(interaction-eval (require (lib "mzlib/for.ss")))
|
||||
|
||||
@title[#:tag "set!"]{Assignment: @scheme[set!]}
|
||||
@title[#:tag "set!"]{Assignment: @racket[set!]}
|
||||
|
||||
@refalso["set!"]{@scheme[set!]}
|
||||
@refalso["set!"]{@racket[set!]}
|
||||
|
||||
Assign to a variable using @scheme[set!]:
|
||||
Assign to a variable using @racket[set!]:
|
||||
|
||||
@specform[(set! id expr)]
|
||||
|
||||
A @scheme[set!] expression evaluates @scheme[_expr] and changes
|
||||
@scheme[_id] (which must be bound in the enclosing environment) to the
|
||||
resulting value. The result of the @scheme[set!] expression itself is
|
||||
A @racket[set!] expression evaluates @racket[_expr] and changes
|
||||
@racket[_id] (which must be bound in the enclosing environment) to the
|
||||
resulting value. The result of the @racket[set!] expression itself is
|
||||
@|void-const|.
|
||||
|
||||
@defexamples[
|
||||
|
@ -47,9 +47,9 @@ greeted
|
|||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "using-set!"]{Guidelines for Using Assignment}
|
||||
|
||||
Although using @scheme[set!] is sometimes appropriate, Scheme style
|
||||
generally discourages the use of @scheme[set!]. The following
|
||||
guidelines may help explain when using @scheme[set!] is appropriate.
|
||||
Although using @racket[set!] is sometimes appropriate, Racket style
|
||||
generally discourages the use of @racket[set!]. The following
|
||||
guidelines may help explain when using @racket[set!] is appropriate.
|
||||
|
||||
@itemize[
|
||||
|
||||
|
@ -136,7 +136,7 @@ guidelines may help explain when using @scheme[set!] is appropriate.
|
|||
]] }
|
||||
|
||||
@item{For cases where stateful objects are necessary or appropriate,
|
||||
then implementing the object's state with @scheme[set!] is
|
||||
then implementing the object's state with @racket[set!] is
|
||||
fine.
|
||||
|
||||
@as-examples[@t{Ok example:}
|
||||
|
@ -159,24 +159,24 @@ resulting code is significantly more readable or if it implements a
|
|||
significantly better algorithm.
|
||||
|
||||
The use of mutable values, such as vectors and hash tables, raises
|
||||
fewer suspicions about the style of a program than using @scheme[set!]
|
||||
directly. Nevertheless, simply replacing @scheme[set!]s in a program
|
||||
with a @scheme[vector-set!]s obviously does not improve the style of
|
||||
fewer suspicions about the style of a program than using @racket[set!]
|
||||
directly. Nevertheless, simply replacing @racket[set!]s in a program
|
||||
with a @racket[vector-set!]s obviously does not improve the style of
|
||||
the program.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Multiple Values: @scheme[set!-values]}
|
||||
@section{Multiple Values: @racket[set!-values]}
|
||||
|
||||
@refalso["set!"]{@scheme[set!-values]}
|
||||
@refalso["set!"]{@racket[set!-values]}
|
||||
|
||||
The @scheme[set!-values] form assigns to multiple variables at once,
|
||||
The @racket[set!-values] form assigns to multiple variables at once,
|
||||
given an expression that produces an appropriate number of values:
|
||||
|
||||
@specform[(set!-values (id ...) expr)]
|
||||
|
||||
This form is equivalent to using @scheme[let-values] to receive
|
||||
multiple results from @scheme[_expr], and then assigning the results
|
||||
individually to the @scheme[_id]s using @scheme[set!].
|
||||
This form is equivalent to using @racket[let-values] to receive
|
||||
multiple results from @racket[_expr], and then assigning the results
|
||||
individually to the @racket[_id]s using @racket[set!].
|
||||
|
||||
@defexamples[
|
||||
(define game
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
@title{Simple Values}
|
||||
|
||||
Scheme values include numbers, booleans, strings, and byte strings. In
|
||||
DrScheme and documentation examples (when you read the documentation
|
||||
Racket values include numbers, booleans, strings, and byte strings. In
|
||||
DrRacket and documentation examples (when you read the documentation
|
||||
in color), value expressions are shown in green.
|
||||
|
||||
@defterm{Numbers} are written in the usual way, including fractions
|
||||
|
@ -14,14 +14,14 @@ and imaginary numbers:
|
|||
|
||||
@moreguide["numbers"]{numbers}
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
1 3.14
|
||||
1/2 6.02e+23
|
||||
1+2i 9999999999999999999999
|
||||
]
|
||||
|
||||
@defterm{Booleans} are @scheme[#t] for true and @scheme[#f] for
|
||||
false. In conditionals, however, all non-@scheme[#f] values are
|
||||
@defterm{Booleans} are @racket[#t] for true and @racket[#f] for
|
||||
false. In conditionals, however, all non-@racket[#f] values are
|
||||
treated as true.
|
||||
|
||||
@moreguide["booleans"]{booleans}
|
||||
|
@ -34,7 +34,7 @@ appear in a string constant.
|
|||
|
||||
@moreguide["strings"]{strings}
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
"Hello, world!"
|
||||
"Benjamin \"Bugsy\" Siegel"
|
||||
"\u03BBx:(\u03BC\u03B1.\u03B1\u2192\u03B1).xx"
|
||||
|
@ -42,11 +42,11 @@ appear in a string constant.
|
|||
|
||||
When a constant is evaluated in the @tech{REPL}, it typically prints the same
|
||||
as its input syntax. In some cases, the printed form is a normalized
|
||||
version of the input syntax. In documentation and in DrScheme's @tech{REPL},
|
||||
version of the input syntax. In documentation and in DrRacket's @tech{REPL},
|
||||
results are printed in blue instead of green to highlight the
|
||||
difference between an input expression and a printed result.
|
||||
|
||||
@examples[
|
||||
(eval:alts (unsyntax (schemevalfont "1.0000")) 1.0000)
|
||||
(eval:alts (unsyntax (schemevalfont "\"Bugs \\u0022Figaro\\u0022 Bunny\"")) "Bugs \u0022Figaro\u0022 Bunny")
|
||||
(eval:alts (unsyntax (racketvalfont "1.0000")) 1.0000)
|
||||
(eval:alts (unsyntax (racketvalfont "\"Bugs \\u0022Figaro\\u0022 Bunny\"")) "Bugs \u0022Figaro\u0022 Bunny")
|
||||
]
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
A program module is written as
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
@#,BNF-seq[@litchar{#lang} @nonterm{langname} @kleenestar{@nonterm{topform}}]
|
||||
]
|
||||
|
||||
|
@ -67,11 +67,11 @@ A definition of the form
|
|||
|
||||
@moreguide["define"]{definitions}
|
||||
|
||||
@schemeblock[@#,val-defn-stx]
|
||||
@racketblock[@#,val-defn-stx]
|
||||
|
||||
binds @nonterm{id} to the result of @nonterm{expr}, while
|
||||
|
||||
@schemeblock[@#,fun-defn-stx]
|
||||
@racketblock[@#,fun-defn-stx]
|
||||
|
||||
binds the first @nonterm{id} to a function (also called a
|
||||
@defterm{procedure}) that takes arguments as named by the remaining
|
||||
|
@ -81,8 +81,8 @@ the last @nonterm{expr}.
|
|||
|
||||
@defexamples[
|
||||
#:eval ex-eval
|
||||
(code:line (define pie 3) (code:comment @#,t{defines @scheme[pie] to be @scheme[3]}))
|
||||
(code:line (define (piece str) (code:comment @#,t{defines @scheme[piece] as a function})
|
||||
(code:line (define pie 3) (code:comment @#,t{defines @racket[pie] to be @racket[3]}))
|
||||
(code:line (define (piece str) (code:comment @#,t{defines @racket[piece] as a function})
|
||||
(substring str 0 pie)) (code:comment @#,t{ of one argument}))
|
||||
pie
|
||||
(piece "key lime")
|
||||
|
@ -113,11 +113,11 @@ evaluated only for some side-effect, such as printing.
|
|||
(bake "apple")
|
||||
]
|
||||
|
||||
Scheme programmers prefer to avoid side-effects, so a definition usually
|
||||
Racket programmers prefer to avoid side-effects, so a definition usually
|
||||
has just one expression in its body. It's
|
||||
important, though, to understand that multiple expressions are allowed
|
||||
in a definition body, because it explains why the following
|
||||
@scheme[nobake] function simply returns its argument:
|
||||
@racket[nobake] function simply returns its argument:
|
||||
|
||||
@def+int[
|
||||
#:eval ex-eval
|
||||
|
@ -126,53 +126,53 @@ in a definition body, because it explains why the following
|
|||
(nobake "green")
|
||||
]
|
||||
|
||||
Within @scheme[nobake], there are no parentheses around
|
||||
@scheme[string-append flavor "jello"], so they are three separate
|
||||
Within @racket[nobake], there are no parentheses around
|
||||
@racket[string-append flavor "jello"], so they are three separate
|
||||
expressions instead of one function-call expression. The expressions
|
||||
@scheme[string-append] and @scheme[flavor] are evaluated, but the
|
||||
@racket[string-append] and @racket[flavor] are evaluated, but the
|
||||
results are never used. Instead, the result of the function is just
|
||||
the result of the final expression, @scheme["jello"].
|
||||
the result of the final expression, @racket["jello"].
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
@section[#:tag "indentation"]{An Aside on Indenting Code}
|
||||
|
||||
Line breaks and indentation are not significant for parsing Scheme
|
||||
programs, but most Scheme programmers use a standard set of conventions
|
||||
Line breaks and indentation are not significant for parsing Racket
|
||||
programs, but most Racket programmers 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
|
||||
DrRacket automatically indents according to the standard style when
|
||||
you type Enter in a program or @tech{REPL} expression. For example, if you
|
||||
hit Enter after typing @litchar{(define (greet name)}, then DrScheme
|
||||
hit Enter after typing @litchar{(define (greet name)}, then DrRacket
|
||||
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
|
||||
region of code, you can select it in DrRacket and hit Tab, and
|
||||
DrRacket will re-indent the code (without inserting any line breaks).
|
||||
Editors like Emacs offer a Racket or 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
|
||||
extra feedback that your parentheses match in the way that you
|
||||
intended. For example, if you leave out a closing parenthesis after
|
||||
the last argument to a function, automatic indentation starts the
|
||||
next line under the first argument, instead of under the
|
||||
@scheme[define] keyword:
|
||||
@racket[define] keyword:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define (halfbake flavor
|
||||
(string-append flavor " creme brulee")))
|
||||
]
|
||||
|
||||
In this case, indentation helps highlight the mistake. In other cases,
|
||||
where the indentation may be normal while an open parenthesis has no
|
||||
matching close parenthesis, both @exec{mzscheme} and DrScheme use the
|
||||
matching close parenthesis, both @exec{racket} and DrRacket use the
|
||||
source's indentation to suggest where a parenthesis might be missing.
|
||||
|
||||
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@section{Identifiers}
|
||||
|
||||
Scheme's syntax for identifiers is especially liberal. Excluding the
|
||||
Racket's syntax for identifiers is especially liberal. Excluding the
|
||||
special characters
|
||||
|
||||
@moreguide["binding"]{identifiers}
|
||||
|
@ -186,41 +186,41 @@ special characters
|
|||
|
||||
and except for the sequences of characters that make number constants,
|
||||
almost any sequence of non-whitespace characters forms an
|
||||
@nonterm{id}. For example @schemeid[substring] is an
|
||||
identifier. Also, @schemeid[string-append] and @schemeid[a+b] are
|
||||
@nonterm{id}. For example @racketid[substring] is an
|
||||
identifier. Also, @racketid[string-append] and @racketid[a+b] are
|
||||
identifiers, as opposed to arithmetic expressions. Here are several
|
||||
more examples:
|
||||
|
||||
@schemeblock[
|
||||
@#,schemeid[+]
|
||||
@#,schemeid[Hfuhruhurr]
|
||||
@#,schemeid[integer?]
|
||||
@#,schemeid[pass/fail]
|
||||
@#,schemeid[john-jacob-jingleheimer-schmidt]
|
||||
@#,schemeid[a-b-c+1-2-3]
|
||||
@racketblock[
|
||||
@#,racketid[+]
|
||||
@#,racketid[Hfuhruhurr]
|
||||
@#,racketid[integer?]
|
||||
@#,racketid[pass/fail]
|
||||
@#,racketid[john-jacob-jingleheimer-schmidt]
|
||||
@#,racketid[a-b-c+1-2-3]
|
||||
]
|
||||
|
||||
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@section{Function Calls@aux-elem{ (Procedure Applications)}}
|
||||
|
||||
We have already seen many function calls, which are called
|
||||
@defterm{procedure applications} in more traditional Scheme
|
||||
@defterm{procedure applications} in more traditional
|
||||
terminology. The syntax of a function call is
|
||||
|
||||
@moreguide["application"]{function calls}
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
#,app-expr-stx
|
||||
]
|
||||
|
||||
where the number of @nonterm{expr}s determines the number of
|
||||
arguments supplied to the function named by @nonterm{id}.
|
||||
|
||||
The @schememodname[scheme] language pre-defines many function
|
||||
identifiers, such as @scheme[substring] and
|
||||
@scheme[string-append]. More examples are below.
|
||||
The @racketmodname[racket] language pre-defines many function
|
||||
identifiers, such as @racket[substring] and
|
||||
@racket[string-append]. More examples are below.
|
||||
|
||||
In example Scheme code throughout the documentation, uses of
|
||||
In example Racket code throughout the documentation, uses of
|
||||
pre-defined names are hyperlinked to the reference manual. So, you can
|
||||
click on an identifier to get full details about its use.
|
||||
|
||||
|
@ -244,19 +244,19 @@ click on an identifier to get full details about its use.
|
|||
]
|
||||
|
||||
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@section{Conditionals with @scheme[if], @scheme[and], @scheme[or], and @scheme[cond]}
|
||||
@section{Conditionals with @racket[if], @racket[and], @racket[or], and @racket[cond]}
|
||||
|
||||
The next simplest kind of expression is an @scheme[if] conditional:
|
||||
The next simplest kind of expression is an @racket[if] conditional:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
#,if-expr-stx
|
||||
]
|
||||
|
||||
@moreguide["conditionals"]{conditionals}
|
||||
|
||||
The first @nonterm{expr} is always evaluated. If it produces a
|
||||
non-@scheme[#f] value, then the second @nonterm{expr} is
|
||||
evaluated for the result of the whole @scheme[if] expression, otherwise
|
||||
non-@racket[#f] value, then the second @nonterm{expr} is
|
||||
evaluated for the result of the whole @racket[if] expression, otherwise
|
||||
the third @nonterm{expr} is evaluated for the result.
|
||||
|
||||
@examples[
|
||||
|
@ -270,15 +270,15 @@ the third @nonterm{expr} is evaluated for the result.
|
|||
(if (equal? "hello" (substring s 0 5))
|
||||
"hi!"
|
||||
"huh?"))
|
||||
(reply "hello scheme")
|
||||
(reply "hello racket")
|
||||
(reply "\u03BBx:(\u03BC\u03B1.\u03B1\u2192\u03B1).xx")
|
||||
]
|
||||
|
||||
Complex conditionals can be formed by nesting @scheme[if]
|
||||
expressions. For example, you could make the @scheme[reply] function
|
||||
Complex conditionals can be formed by nesting @racket[if]
|
||||
expressions. For example, you could make the @racket[reply] function
|
||||
work when given non-strings:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define (reply s)
|
||||
(if (string? s)
|
||||
(if (equal? "hello" (substring s 0 5))
|
||||
|
@ -287,10 +287,10 @@ work when given non-strings:
|
|||
"huh?"))
|
||||
]
|
||||
|
||||
Instead of duplicating the @scheme["huh?"] case, this function is
|
||||
Instead of duplicating the @racket["huh?"] case, this function is
|
||||
better written as
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define (reply s)
|
||||
(if (if (string? s)
|
||||
(equal? "hello" (substring s 0 5))
|
||||
|
@ -299,20 +299,20 @@ better written as
|
|||
"huh?"))
|
||||
]
|
||||
|
||||
but these kinds of nested @scheme[if]s are difficult to read. Scheme
|
||||
provides more readable shortcuts through the @scheme[and] and
|
||||
@scheme[or] forms, which work with any number of expressions:
|
||||
but these kinds of nested @racket[if]s are difficult to read. Racket
|
||||
provides more readable shortcuts through the @racket[and] and
|
||||
@racket[or] forms, which work with any number of expressions:
|
||||
|
||||
@moreguide["and+or"]{@scheme[and] and @scheme[or]}
|
||||
@moreguide["and+or"]{@racket[and] and @racket[or]}
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
#,and-expr-stx
|
||||
#,or-expr-stx
|
||||
]
|
||||
|
||||
The @scheme[and] form short-circuits: it stops and returns @scheme[#f]
|
||||
when an expression produces @scheme[#f], otherwise it keeps
|
||||
going. The @scheme[or] form similarly short-circuits when it
|
||||
The @racket[and] form short-circuits: it stops and returns @racket[#f]
|
||||
when an expression produces @racket[#f], otherwise it keeps
|
||||
going. The @racket[or] form similarly short-circuits when it
|
||||
encounters a true result.
|
||||
|
||||
@defexamples[
|
||||
|
@ -322,14 +322,14 @@ encounters a true result.
|
|||
(equal? "hello" (substring s 0 5)))
|
||||
"hi!"
|
||||
"huh?"))
|
||||
(reply "hello scheme")
|
||||
(reply "hello racket")
|
||||
(reply 17)
|
||||
]
|
||||
|
||||
Another common pattern of nested @scheme[if]s involves a sequence of
|
||||
Another common pattern of nested @racket[if]s involves a sequence of
|
||||
tests, each with its own result:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define (reply-more s)
|
||||
(if (equal? "hello" (substring s 0 5))
|
||||
"hi!"
|
||||
|
@ -340,25 +340,25 @@ tests, each with its own result:
|
|||
"huh?"))))
|
||||
]
|
||||
|
||||
The shorthand for a sequence of tests is the @scheme[cond] form:
|
||||
The shorthand for a sequence of tests is the @racket[cond] form:
|
||||
|
||||
@moreguide["cond"]{@scheme[cond]}
|
||||
@moreguide["cond"]{@racket[cond]}
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
#,cond-expr-stx
|
||||
]
|
||||
|
||||
A @scheme[cond] form contains a sequence of clauses between square
|
||||
A @racket[cond] form contains a sequence of clauses between square
|
||||
brackets. In each clause, the first @nonterm{expr} is a test
|
||||
expression. If it produces true, then the clause's remaining
|
||||
@nonterm{expr}s are evaluated, and the last one in the clause provides
|
||||
the answer for the entire @scheme[cond] expression; the rest of the
|
||||
clauses are ignored. If the test @nonterm{expr} produces @scheme[#f],
|
||||
the answer for the entire @racket[cond] expression; the rest of the
|
||||
clauses are ignored. If the test @nonterm{expr} produces @racket[#f],
|
||||
then the clause's remaining @nonterm{expr}s are ignored, and
|
||||
evaluation continues with the next clause. The last clause can use
|
||||
@scheme[else] as a synonym for a @scheme[#t] test expression.
|
||||
@racket[else] as a synonym for a @racket[#t] test expression.
|
||||
|
||||
Using @scheme[cond], the @scheme[reply-more] function can be more
|
||||
Using @racket[cond], the @racket[reply-more] function can be more
|
||||
clearly written as follows:
|
||||
|
||||
@def+int[
|
||||
|
@ -371,17 +371,17 @@ clearly written as follows:
|
|||
[(equal? "?" (substring s (- (string-length s) 1)))
|
||||
"I don't know"]
|
||||
[else "huh?"]))
|
||||
(reply-more "hello scheme")
|
||||
(reply-more "hello racket")
|
||||
(reply-more "goodbye cruel world")
|
||||
(reply-more "what is your favorite color?")
|
||||
(reply-more "mine is lime green")
|
||||
]
|
||||
|
||||
The use of square brackets for @scheme[cond] clauses is a
|
||||
convention. In Scheme, parentheses and square brackets are actually
|
||||
The use of square brackets for @racket[cond] clauses is a
|
||||
convention. In Racket, 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.
|
||||
few key places makes Racket code even more readable.
|
||||
|
||||
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@section{Function Calls, Again}
|
||||
|
@ -392,12 +392,12 @@ expression for the function, instead of just an @nonterm{id}:
|
|||
|
||||
@moreguide["application"]{function calls}
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
#,app2-expr-stx
|
||||
]
|
||||
|
||||
The first @nonterm{expr} is often an @nonterm{id}, such
|
||||
as @scheme[string-append] or @scheme[+], but it can be anything that
|
||||
as @racket[string-append] or @racket[+], but it can be anything that
|
||||
evaluates to a function. For example, it can be a conditional
|
||||
expression:
|
||||
|
||||
|
@ -419,12 +419,12 @@ parentheses around an expression, you'll most often get an ``expected
|
|||
a procedure'' error like this one.
|
||||
|
||||
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@section{Anonymous Functions with @scheme[lambda]}
|
||||
@section{Anonymous Functions with @racket[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
|
||||
Programming in Racket would be tedious if you had to name all of your
|
||||
numbers. Instead of writing @racket[(+ 1 2)], you'd have to write
|
||||
|
||||
@moreguide["lambda"]{@scheme[lambda]}
|
||||
@moreguide["lambda"]{@racket[lambda]}
|
||||
|
||||
@interaction[
|
||||
(define a 1)
|
||||
|
@ -433,9 +433,9 @@ numbers. Instead of writing @scheme[(+ 1 2)], you'd have to write
|
|||
]
|
||||
|
||||
It turns out that having to name all your functions can be tedious,
|
||||
too. For example, you might have a function @scheme[twice] that takes
|
||||
a function and an argument. Using @scheme[twice] is convenient if you
|
||||
already have a name for the function, such as @scheme[sqrt]:
|
||||
too. For example, you might have a function @racket[twice] that takes
|
||||
a function and an argument. Using @racket[twice] is convenient if you
|
||||
already have a name for the function, such as @racket[sqrt]:
|
||||
|
||||
@def+int[
|
||||
#:eval ex-eval
|
||||
|
@ -445,7 +445,7 @@ already have a name for the function, such as @scheme[sqrt]:
|
|||
]
|
||||
|
||||
If you want to call a function that is not yet defined, you could
|
||||
define it, and then pass it to @scheme[twice]:
|
||||
define it, and then pass it to @racket[twice]:
|
||||
|
||||
@def+int[
|
||||
#:eval ex-eval
|
||||
|
@ -454,22 +454,22 @@ define it, and then pass it to @scheme[twice]:
|
|||
(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 function directly. The @scheme[lambda] form is followed by
|
||||
But if the call to @racket[twice] is the only place where
|
||||
@racket[louder] is used, it's a shame to have to write a whole
|
||||
definition. In Racket, you can use a @racket[lambda] expression to
|
||||
produce a function directly. The @racket[lambda] form is followed by
|
||||
identifiers for the function's arguments, and then the function's
|
||||
body expressions:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
#,lambda-expr-stx
|
||||
]
|
||||
|
||||
Evaluating a @scheme[lambda] form by itself produces a function:
|
||||
Evaluating a @racket[lambda] form by itself produces a function:
|
||||
|
||||
@interaction[(lambda (s) (string-append s "!"))]
|
||||
|
||||
Using @scheme[lambda], the above call to @scheme[twice] can be
|
||||
Using @racket[lambda], the above call to @racket[twice] can be
|
||||
re-written as
|
||||
|
||||
@interaction[
|
||||
|
@ -480,7 +480,7 @@ re-written as
|
|||
"hello")
|
||||
]
|
||||
|
||||
Another use of @scheme[lambda] is as a result for a function that
|
||||
Another use of @racket[lambda] is as a result for a function that
|
||||
generates functions:
|
||||
|
||||
@def+int[
|
||||
|
@ -492,11 +492,11 @@ generates functions:
|
|||
(twice (make-add-suffix "...") "hello")
|
||||
]
|
||||
|
||||
Scheme is a @defterm{lexically scoped} language, which means that
|
||||
@scheme[s2] in the function returned by @scheme[make-add-suffix]
|
||||
Racket is a @defterm{lexically scoped} language, which means that
|
||||
@racket[s2] in the function returned by @racket[make-add-suffix]
|
||||
always refers to the argument for the call that created the
|
||||
function. In other words, the @scheme[lambda]-generated function
|
||||
``remembers'' the right @scheme[s2]:
|
||||
function. In other words, the @racket[lambda]-generated function
|
||||
``remembers'' the right @racket[s2]:
|
||||
|
||||
@interaction[
|
||||
#:eval ex-eval
|
||||
|
@ -506,12 +506,12 @@ function. In other words, the @scheme[lambda]-generated function
|
|||
(twice louder "really")
|
||||
]
|
||||
|
||||
We have so far referred to definitions of the form @scheme[(define
|
||||
We have so far referred to definitions of the form @racket[(define
|
||||
@#,nonterm{id} @#,nonterm{expr})] as ``non-function
|
||||
definitions.'' This characterization is misleading, because the
|
||||
@nonterm{expr} could be a @scheme[lambda] form, in which case
|
||||
@nonterm{expr} could be a @racket[lambda] form, in which case
|
||||
the definition is equivalent to using the ``function'' definition
|
||||
form. For example, the following two definitions of @scheme[louder]
|
||||
form. For example, the following two definitions of @racket[louder]
|
||||
are equivalent:
|
||||
|
||||
@defs+int[
|
||||
|
@ -525,22 +525,22 @@ are equivalent:
|
|||
louder
|
||||
]
|
||||
|
||||
Note that the expression for @scheme[louder] in the second case is an
|
||||
``anonymous'' function written with @scheme[lambda], but, if
|
||||
Note that the expression for @racket[louder] in the second case is an
|
||||
``anonymous'' function written with @racket[lambda], but, if
|
||||
possible, the compiler infers a name, anyway, to make printing and
|
||||
error reporting as informative as possible.
|
||||
|
||||
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@section[#:tag "local-binding-intro"]{Local Binding with
|
||||
@scheme[define], @scheme[let], and @scheme[let*]}
|
||||
@racket[define], @racket[let], and @racket[let*]}
|
||||
|
||||
It's time to retract another simplification in our grammar of
|
||||
Scheme. In the body of a function, definitions can appear before the
|
||||
Racket. In the body of a function, definitions can appear before the
|
||||
body expressions:
|
||||
|
||||
@moreguide["intdefs"]{local (internal) definitions}
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
#,fun-defn2-stx
|
||||
#,lambda2-expr-stx
|
||||
]
|
||||
|
@ -550,8 +550,8 @@ function 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?]})
|
||||
(define (starts? s2) (code:comment @#,t{local to @racket[converse]})
|
||||
(define len2 (string-length s2)) (code:comment @#,t{local to @racket[starts?]})
|
||||
(and (>= (string-length s) len2)
|
||||
(equal? s2 (substring s 0 len2))))
|
||||
(cond
|
||||
|
@ -560,24 +560,24 @@ function body.
|
|||
[else "huh?"]))
|
||||
(converse "hello!")
|
||||
(converse "urp")
|
||||
(eval:alts (code:line starts? (code:comment @#,t{outside of @scheme[converse], so...}))
|
||||
(eval:alts (code:line starts? (code:comment @#,t{outside of @racket[converse], so...}))
|
||||
(parameterize ([current-namespace (make-base-namespace)]) (eval 'starts?)))
|
||||
]
|
||||
|
||||
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.
|
||||
Another way to create local bindings is the @racket[let] form. An
|
||||
advantage of @racket[let] is that it can be used in any expression
|
||||
position. Also, @racket[let] binds many identifiers at once, instead
|
||||
of requiring a separate @racket[define] for each identifier.
|
||||
|
||||
@moreguide["intdefs"]{@scheme[let] and @scheme[let*]}
|
||||
@moreguide["intdefs"]{@racket[let] and @racket[let*]}
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
#,let-expr-stx
|
||||
]
|
||||
|
||||
Each binding clause is an @nonterm{id} and a
|
||||
@nonterm{expr} surrounded by square brackets, and the
|
||||
expressions after the clauses are the body of the @scheme[let]. In
|
||||
expressions after the clauses are the body of the @racket[let]. In
|
||||
each clause, the @nonterm{id} is bound to the result of the
|
||||
@nonterm{expr} for use in the body.
|
||||
|
||||
|
@ -590,9 +590,9 @@ each clause, the @nonterm{id} is bound to the result of the
|
|||
[else "cat's game"]))
|
||||
]
|
||||
|
||||
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
|
||||
The bindings of a @racket[let] form are available only in the body of
|
||||
the @racket[let], so the binding clauses cannot refer to each
|
||||
other. The @racket[let*] form, in contrast, allows later clauses to
|
||||
use earlier bindings:
|
||||
|
||||
@interaction[
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
|
||||
@title[#:tag "symbols"]{Symbols}
|
||||
|
||||
A @deftech{symbol} is an atomic value that prints like an identifier.
|
||||
An expression that starts with @litchar{'} and continues with an
|
||||
identifier produces a symbol value.
|
||||
A @deftech{symbol} is an atomic value that prints like an identifier
|
||||
preceded with @litchar{'}. An expression that starts with @litchar{'}
|
||||
and continues with an identifier produces a symbol value.
|
||||
|
||||
@examples[
|
||||
'a
|
||||
|
@ -15,13 +15,13 @@ identifier produces a symbol value.
|
|||
]
|
||||
|
||||
For any sequence of characters, exactly one corresponding symbol is
|
||||
@defterm{interned}; calling the @scheme[string->symbol] procedure, or
|
||||
@scheme[read]ing a syntactic identifier, produces an interned
|
||||
@defterm{interned}; calling the @racket[string->symbol] procedure, or
|
||||
@racket[read]ing a syntactic identifier, produces an interned
|
||||
symbol. Since interned symbols can be cheaply compared with
|
||||
@scheme[eq?] (and thus @scheme[eqv?] or @scheme[equal?]), they serves
|
||||
@racket[eq?] (and thus @racket[eqv?] or @racket[equal?]), they serves
|
||||
as a convenient values to use for tags and enumerations.
|
||||
|
||||
Symbols are case-sensitive. By using a @schemefont{#ci} prefix or in
|
||||
Symbols are case-sensitive. By using a @racketfont{#ci} prefix or in
|
||||
other ways, the reader can be made to case-fold character sequences to
|
||||
arrive at a symbol, but the reader preserves case by default.
|
||||
|
||||
|
@ -30,11 +30,11 @@ arrive at a symbol, but the reader preserves case by default.
|
|||
(eq? 'a (string->symbol "a"))
|
||||
(eq? 'a 'b)
|
||||
(eq? 'a 'A)
|
||||
(eval:alts @#,elem{@schemefont{#ci}@schemevalfont{'A}} #ci'A)
|
||||
(eval:alts @#,elem{@racketfont{#ci}@racketvalfont{'A}} #ci'A)
|
||||
]
|
||||
|
||||
Any string (i.e., any character sequence) can be supplied to
|
||||
@scheme[string->symbol] to obtain the corresponding symbol. For reader
|
||||
@racket[string->symbol] to obtain the corresponding symbol. For reader
|
||||
input, any character can appear directly in an identifier, except for
|
||||
whitespace and the following special characters:
|
||||
|
||||
|
@ -61,7 +61,7 @@ special characters or that might otherwise look like numbers.
|
|||
|
||||
@refdetails/gory["parse-symbol"]{the syntax of symbols}
|
||||
|
||||
The @scheme[display] form of a symbol is the same as the corresponding
|
||||
The @racket[display] form of a symbol is the same as the corresponding
|
||||
string.
|
||||
|
||||
@examples[
|
||||
|
@ -69,9 +69,9 @@ string.
|
|||
(display '|6|)
|
||||
]
|
||||
|
||||
The @scheme[gensym] and @scheme[string->uninterned-symbol] procedures
|
||||
The @racket[gensym] and @racket[string->uninterned-symbol] procedures
|
||||
generate fresh @defterm{uninterned} symbols that are not equal
|
||||
(according to @scheme[eq?]) to any previously interned or uninterned
|
||||
(according to @racket[eq?]) to any previously interned or uninterned
|
||||
symbol. Uninterned symbols are useful as fresh tags that cannot be
|
||||
confused with any other value.
|
||||
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
scribble/eval
|
||||
"guide-utils.ss")
|
||||
|
||||
@title[#:tag "to-scheme" #:style 'toc]{Scheme Essentials}
|
||||
@title[#:tag "to-scheme" #:style 'toc]{Racket Essentials}
|
||||
|
||||
This chapter provides a quick introduction to Scheme as background for
|
||||
the rest of the guide. Readers with some Scheme experience can safely
|
||||
This chapter provides a quick introduction to Racket as background for
|
||||
the rest of the guide. Readers with some Racket experience can safely
|
||||
skip to @secref["datatypes"].
|
||||
|
||||
@local-table-of-contents[]
|
||||
|
|
|
@ -1,35 +1,36 @@
|
|||
#lang scribble/doc
|
||||
@(require scribble/manual
|
||||
scribble/eval
|
||||
scheme/list
|
||||
racket/list
|
||||
"guide-utils.ss"
|
||||
|
||||
(for-label scheme/list))
|
||||
(for-label racket/list
|
||||
(only-in racket/class is-a?)))
|
||||
|
||||
@(define list-eval (make-base-eval))
|
||||
@(interaction-eval #:eval list-eval (require scheme/list))
|
||||
@(interaction-eval #:eval list-eval (require racket/list))
|
||||
|
||||
@title{Pairs, Lists, and Scheme Syntax}
|
||||
@title{Pairs, Lists, and Racket Syntax}
|
||||
|
||||
The @scheme[cons] function actually accepts any two values, not just
|
||||
The @racket[cons] function actually accepts any two values, not just
|
||||
a list for the second argument. When the second argument is not
|
||||
@scheme[empty] and not itself produced by @scheme[cons], the result prints
|
||||
in a special way. The two values joined with @scheme[cons] are printed
|
||||
@racket[empty] and not itself produced by @racket[cons], the result prints
|
||||
in a special way. The two values joined with @racket[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?] function is @scheme[pair?],
|
||||
Thus, a value produced by @racket[cons] is not always a list. In
|
||||
general, the result of @racket[cons] is a @defterm{pair}. The more
|
||||
traditional name for the @racket[cons?] function is @racket[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
|
||||
The name @racket[rest] also makes less sense for non-list pairs; the
|
||||
more traditional names for @racket[first] and @racket[rest] are
|
||||
@racket[car] and @racket[cdr], respectively. (Granted, the traditional
|
||||
names are also nonsense. Just remember that ``a'' comes before ``d,''
|
||||
and @scheme[cdr] is pronounced ``could-er.'')
|
||||
and @racket[cdr] is pronounced ``could-er.'')
|
||||
|
||||
@examples[
|
||||
#:eval list-eval
|
||||
|
@ -42,24 +43,24 @@ and @scheme[cdr] is pronounced ``could-er.'')
|
|||
|
||||
@close-eval[list-eval]
|
||||
|
||||
Scheme's pair datatype and its relation to lists is essentially a
|
||||
Racket'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,
|
||||
funny names @racket[car] and @racket[cdr]. Pairs are deeply wired into
|
||||
to the culture, specification, and implementation of Racket, 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]:
|
||||
@racket[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] function takes a list of pairs, where the
|
||||
@scheme[car] of each pair is a key and the @scheme[cdr] is an
|
||||
@racket[make-hash] function takes a list of pairs, where the
|
||||
@racket[car] of each pair is a key and the @racket[cdr] is an
|
||||
arbitrary value.
|
||||
|
||||
The only thing more confusing to new Schemers than non-list pairs is
|
||||
The only thing more confusing to new Racketeers than non-list pairs is
|
||||
the printing convention for pairs where the second element @italic{is}
|
||||
a pair, but @italic{is not} a list:
|
||||
|
||||
|
@ -68,12 +69,12 @@ a pair, but @italic{is not} a list:
|
|||
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)].
|
||||
matching close parenthesis. Thus, @racketresultfont{`(0 . (1 . 2))}
|
||||
becomes @racketresult[`(0 1 . 2)], and
|
||||
@racketresultfont{`(1 . (2 . (3 . ())))} becomes @racketresult[`(1 2 3)].
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "quoting-lists"]{Quoting Pairs and Symbols with @scheme[quote]}
|
||||
@section[#:tag "quoting-lists"]{Quoting Pairs and Symbols with @racket[quote]}
|
||||
|
||||
After you see
|
||||
|
||||
|
@ -82,79 +83,86 @@ After you see
|
|||
]
|
||||
|
||||
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 of
|
||||
lists that prints as @schemeresult[((1) (2) (3))]. The @scheme[quote]
|
||||
way to write just @racket[((1) (2) (3))] and have it mean the list of
|
||||
lists that prints as @racketresult[`((1) (2) (3))]. The @racket[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] ()) '())
|
||||
(eval:alts (@#,racket[quote] ((1) (2) (3))) '((1) (2) (3)))
|
||||
(eval:alts (@#,racket[quote] ("red" "green" "blue")) '("red" "green" "blue"))
|
||||
(eval:alts (@#,racket[quote] ()) '())
|
||||
]
|
||||
|
||||
The @scheme[quote] form works with the dot notation, too, whether the
|
||||
The @racket[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)))
|
||||
(eval:alts (@#,racket[quote] (1 . 2)) '(1 . 2))
|
||||
(eval:alts (@#,racket[quote] (0 @#,racketparenfont{.} (1 . 2))) '(0 . (1 . 2)))
|
||||
]
|
||||
|
||||
Naturally, lists of any kind 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")))
|
||||
(eval:alts (@#,racket[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:
|
||||
If you wrap an identifier with @racket[quote], then you get output
|
||||
that looks like an identifier, but with a @litchar{'} prefix:
|
||||
|
||||
@interaction[
|
||||
(eval:alts (@#,scheme[quote] jane-doe) 'jane-doe)
|
||||
(eval:alts (@#,racket[quote] jane-doe) 'jane-doe)
|
||||
]
|
||||
|
||||
A value that prints like an identifier is a @defterm{symbol}. In the
|
||||
same way that parenthesized 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. In particular, the symbol @racket[(@#,racket[quote]
|
||||
@#,racketidfont{map})] has nothing to do with the @racketidfont{map}
|
||||
identifier or the predefined function that is bound to
|
||||
@scheme[map], except that the symbol and the identifier happen
|
||||
@racket[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 functions
|
||||
@scheme[symbol->string] and @scheme[string->symbol] convert between
|
||||
@racket[symbol->string] and @racket[string->symbol] convert between
|
||||
them.
|
||||
|
||||
@examples[
|
||||
map
|
||||
(eval:alts (@#,scheme[quote] @#,schemeidfont{map}) 'map)
|
||||
(eval:alts (symbol? (@#,scheme[quote] @#,schemeidfont{map})) (symbol? 'map))
|
||||
(eval:alts (@#,racket[quote] @#,racketidfont{map}) 'map)
|
||||
(eval:alts (symbol? (@#,racket[quote] @#,racketidfont{map})) (symbol? 'map))
|
||||
(symbol? map)
|
||||
(procedure? map)
|
||||
(string->symbol "map")
|
||||
(eval:alts (symbol->string (@#,scheme[quote] @#,schemeidfont{map})) (symbol->string 'map))
|
||||
(eval:alts (symbol->string (@#,racket[quote] @#,racketidfont{map})) (symbol->string 'map))
|
||||
]
|
||||
|
||||
When @scheme[quote] is used on a parenthesized sequence of
|
||||
When @racket[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))))
|
||||
(eval:alts (car (@#,racket[quote] (@#,racketidfont{road} @#,racketidfont{map}))) (car '(road map)))
|
||||
(eval:alts (symbol? (car (@#,racket[quote] (@#,racketidfont{road} @#,racketidfont{map})))) (symbol? (car '(road map))))
|
||||
]
|
||||
|
||||
When a symbol is inside a
|
||||
list that is printed with @litchar{`}, the @litchar{'} on the symbol
|
||||
is omitted, since @litchar{`} is doing the job already:
|
||||
|
||||
@interaction[
|
||||
(eval:alts (@#,racket[quote] (@#,racketidfont{road} @#,racketidfont{map})) '(road map))
|
||||
]
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Abbreviating @scheme[quote] with @schemevalfont{'}}
|
||||
@section{Abbreviating @racket[quote] with @racketvalfont{'}}
|
||||
|
||||
If @scheme[(@#,scheme[quote] (1 2 3))] still seems like too much
|
||||
If @racket[(@#,racket[quote] (1 2 3))] still seems like too much
|
||||
typing, you can abbreviate by just putting @litchar{'} in front of
|
||||
@scheme[(1 2 3)]:
|
||||
@racket[(1 2 3)]:
|
||||
|
||||
@interaction[
|
||||
'(1 2 3)
|
||||
|
@ -162,31 +170,30 @@ typing, you can abbreviate by just putting @litchar{'} in front of
|
|||
'((1 2 3) road ("a" "b" "c"))
|
||||
]
|
||||
|
||||
In the documentation, @litchar{'} is printed in green along with the
|
||||
In the documentation, @litchar{'} within an expression 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
|
||||
constant. In DrRacket, only the @litchar{'} is colored green. DrRacket
|
||||
is more precisely correct, because the meaning of @racket[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
|
||||
A @litchar{'} expands to a @racket[quote] form in quite a literal
|
||||
way. You can see this if you put a @litchar{'} in front of a form that has a
|
||||
@litchar{'}:
|
||||
|
||||
@interaction[
|
||||
(eval:alts (car '(@#,schemevalfont{quote} @#,schemevalfont{road})) 'quote)
|
||||
(eval:alts (car '(@#,racketvalfont{quote} @#,racketvalfont{road})) 'quote)
|
||||
(car ''road)
|
||||
]
|
||||
|
||||
Beware, however, that the @tech{REPL}'s printer recognizes the symbol
|
||||
@schemeidfont{quote} when printing output, and then it uses
|
||||
@schemeidfont{'} in the output:
|
||||
@racketidfont{quote} when printing output, and then it uses
|
||||
@racketidfont{'} in the output:
|
||||
|
||||
@interaction[
|
||||
'road
|
||||
''road
|
||||
(eval:alts '(@#,schemevalfont{quote} @#,schemevalfont{road}) ''road)
|
||||
(eval:alts (list (@#,racketvalfont{quote} (@#,racketvalfont{quote} @#,racketvalfont{road}))) '('road))
|
||||
(list ''road)
|
||||
]
|
||||
|
||||
@; FIXME:
|
||||
|
@ -194,13 +201,48 @@ Beware, however, that the @tech{REPL}'s printer recognizes the symbol
|
|||
@; different than what "list" creates
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "lists-and-syntax"]{Lists and Scheme Syntax}
|
||||
@section{Quasiquoting with @racketvalfont{`}}
|
||||
|
||||
At this point, you may wonder why a symbol that is written with
|
||||
@litchar{'} prints back with @litchar{'}, while a list that is written
|
||||
with @litchar{'} prints back with @litchar{`}:
|
||||
|
||||
@interaction[
|
||||
'road
|
||||
'(left right)
|
||||
]
|
||||
|
||||
The @litchar{`} character is a shorthand for @racket[quasiquote] in
|
||||
the same way that @litchar{'} is short for @racket[quote]. The
|
||||
@racket[quasiquote] form is like @scheme[quote], except that the
|
||||
content of a @scheme[quasiquote]d form can escape back to a Racket
|
||||
expression using @racket[unquote], which is abbreviated @litchar{,}:
|
||||
|
||||
@moreguide["qq"]{@racket[quasiquote]}
|
||||
|
||||
@interaction[
|
||||
`(1 ,(+ 1 1) "buckle my shoe")
|
||||
]
|
||||
|
||||
The value printer in Racket uses @litchar{`} for a lists in case it
|
||||
must escape to print certain kinds of values that cannot be written
|
||||
directly under @scheme[quote]. For example, a source-location record
|
||||
is created with the @racket[srcloc] function, and it prints like an
|
||||
equivalent call to @racket[srcloc]:
|
||||
|
||||
@interaction[
|
||||
(srcloc "file.rkt" 1 0 1 (+ 4 4))
|
||||
(list 'here (srcloc "file.rkt" 1 0 1 8) 'there)
|
||||
]
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "lists-and-syntax"]{Lists and Racket 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.
|
||||
seen @racket[quote], you're ready to understand the main way in which
|
||||
we have been simplifying Racket's true syntax.
|
||||
|
||||
The syntax of Scheme is not defined directly in terms of character
|
||||
The syntax of Racket is not defined directly in terms of character
|
||||
streams. Instead, the syntax is determined by two layers:
|
||||
|
||||
@itemize[
|
||||
|
@ -223,13 +265,13 @@ 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))
|
||||
(eval:alts (+ 1 . @#,racket[(2)]) (+ 1 2))
|
||||
]
|
||||
|
||||
This works because @scheme[(+ 1 . @#,scheme[(2)])] is just another
|
||||
way of writing @scheme[(+ 1 2)]. It is practically never a good idea
|
||||
This works because @racket[(+ 1 . @#,racket[(2)])] is just another
|
||||
way of writing @racket[(+ 1 2)]. It is practically never a good idea
|
||||
to write application expressions using this dot notation; it's just a
|
||||
consequence of the way Scheme's syntax is defined.
|
||||
consequence of the way Racket's syntax is defined.
|
||||
|
||||
Normally, @litchar{.} is allowed by the reader only with a
|
||||
parenthesized sequence, and only before the last element of the
|
||||
|
@ -245,6 +287,6 @@ conversion enables a kind of general infix notation:
|
|||
]
|
||||
|
||||
This two-dot convention is non-traditional, and it has essentially
|
||||
nothing to do with the dot notation for non-list pairs. PLT Scheme
|
||||
nothing to do with the dot notation for non-list pairs. Racket
|
||||
programmers use the infix convention sparingly---mostly for asymmetric
|
||||
binary operators such as @scheme[<] and @scheme[is-a?].
|
||||
binary operators such as @racket[<] and @racket[is-a?].
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
scribble/eval
|
||||
"guide-utils.ss"
|
||||
|
||||
(for-label scheme/unit
|
||||
scheme/class))
|
||||
(for-label racket/unit
|
||||
racket/class))
|
||||
|
||||
@(define toy-eval (make-base-eval))
|
||||
|
||||
@(interaction-eval #:eval toy-eval (require scheme/unit))
|
||||
@(interaction-eval #:eval toy-eval (require racket/unit))
|
||||
|
||||
@(define-syntax-rule (schememod/eval [pre ...] form more ...)
|
||||
@(define-syntax-rule (racketmod/eval [pre ...] form more ...)
|
||||
(begin
|
||||
(schememod pre ... form more ...)
|
||||
(racketmod pre ... form more ...)
|
||||
(interaction-eval #:eval toy-eval form)))
|
||||
|
||||
@title[#:tag "units" #:style 'toc]{Units@aux-elem{ (Components)}}
|
||||
|
@ -40,15 +40,15 @@ re-exports some variables from the linked units for further linking.
|
|||
|
||||
The interface of a unit is described in terms of
|
||||
@deftech{signatures}. Each signature is defined (normally within a
|
||||
@scheme[module]) using @scheme[define-signature]. For example, the
|
||||
@racket[module]) using @racket[define-signature]. For example, the
|
||||
following signature, placed in a @filepath{toy-factory-sig.ss} file,
|
||||
describes the exports of a component that implements a toy factory:
|
||||
|
||||
@margin-note{By convention, signature names with @litchar{^}.}
|
||||
|
||||
@schememod/eval[[#:file
|
||||
@racketmod/eval[[#:file
|
||||
"toy-factory-sig.ss"
|
||||
scheme]
|
||||
racket]
|
||||
|
||||
(define-signature toy-factory^
|
||||
(build-toys (code:comment #, @tt{(integer? -> (listof toy?))})
|
||||
|
@ -59,15 +59,15 @@ scheme]
|
|||
(provide toy-factory^)
|
||||
]
|
||||
|
||||
An implementation of the @scheme[toy-factory^] signature is written
|
||||
using @scheme[define-unit] with an @scheme[export] clause that names
|
||||
@scheme[toy-factory^]:
|
||||
An implementation of the @racket[toy-factory^] signature is written
|
||||
using @racket[define-unit] with an @racket[export] clause that names
|
||||
@racket[toy-factory^]:
|
||||
|
||||
@margin-note{By convention, unit names with @litchar["@"].}
|
||||
|
||||
@schememod/eval[[#:file
|
||||
@racketmod/eval[[#:file
|
||||
"simple-factory-unit.ss"
|
||||
scheme
|
||||
racket
|
||||
|
||||
(require "toy-factory-sig.ss")]
|
||||
|
||||
|
@ -89,16 +89,16 @@ scheme
|
|||
(provide simple-factory@)
|
||||
]
|
||||
|
||||
The @scheme[toy-factory^] signature also could be referenced by a unit
|
||||
The @racket[toy-factory^] signature also could be referenced by a unit
|
||||
that needs a toy factory to implement something else. In that case,
|
||||
@scheme[toy-factory^] would be named in an @scheme[import] clause.
|
||||
@racket[toy-factory^] would be named in an @racket[import] clause.
|
||||
For example, a toy store would get toys from a toy factory. (Suppose,
|
||||
for the sake of an example with interesting features, that the store
|
||||
is willing to sell only toys in a particular color.)
|
||||
|
||||
@schememod/eval[[#:file
|
||||
@racketmod/eval[[#:file
|
||||
"toy-store-sig.ss"
|
||||
scheme]
|
||||
racket]
|
||||
|
||||
(define-signature toy-store^
|
||||
(store-color (code:comment #, @tt{(-> symbol?)})
|
||||
|
@ -108,9 +108,9 @@ scheme]
|
|||
(provide toy-store^)
|
||||
]
|
||||
|
||||
@schememod/eval[[#:file
|
||||
@racketmod/eval[[#:file
|
||||
"toy-store-unit.ss"
|
||||
scheme
|
||||
racket
|
||||
|
||||
(require "toy-store-sig.ss"
|
||||
"toy-factory-sig.ss")]
|
||||
|
@ -142,15 +142,15 @@ scheme
|
|||
Note that @filepath{toy-store-unit.ss} imports
|
||||
@filepath{toy-factory-sig.ss}, but not
|
||||
@filepath{simple-factory-unit.ss}. Consequently, the
|
||||
@scheme[toy-store@] unit relies only on the specification of a toy
|
||||
@racket[toy-store@] unit relies only on the specification of a toy
|
||||
factory, not on a specific implementation.
|
||||
|
||||
@; ----------------------------------------
|
||||
|
||||
@section{Invoking Units}
|
||||
|
||||
The @scheme[simple-factory@] unit has no imports, so it can be
|
||||
@tech{invoked} directly using @scheme[invoke-unit]:
|
||||
The @racket[simple-factory@] unit has no imports, so it can be
|
||||
@tech{invoked} directly using @racket[invoke-unit]:
|
||||
|
||||
@interaction[
|
||||
#:eval toy-eval
|
||||
|
@ -158,9 +158,9 @@ The @scheme[simple-factory@] unit has no imports, so it can be
|
|||
(invoke-unit simple-factory@)
|
||||
]
|
||||
|
||||
The @scheme[invoke-unit] form does not make the body definitions
|
||||
The @racket[invoke-unit] form does not make the body definitions
|
||||
available, however, so we cannot build any toys with this factory. The
|
||||
@scheme[define-values/invoke-unit] form binds the identifiers of a
|
||||
@racket[define-values/invoke-unit] form binds the identifiers of a
|
||||
signature to the values supplied by a unit (to be @tech{invoked}) that
|
||||
implements the signature:
|
||||
|
||||
|
@ -170,16 +170,16 @@ implements the signature:
|
|||
(build-toys 3)
|
||||
]
|
||||
|
||||
Since @scheme[simple-factory@] exports the @scheme[toy-factory^]
|
||||
signature, each identifier in @scheme[toy-factory^] is defined by the
|
||||
@scheme[define-values/invoke-unit/infer] form. The
|
||||
@schemeidfont{/infer} part of the form name indicates that the
|
||||
Since @racket[simple-factory@] exports the @racket[toy-factory^]
|
||||
signature, each identifier in @racket[toy-factory^] is defined by the
|
||||
@racket[define-values/invoke-unit/infer] form. The
|
||||
@racketidfont{/infer} part of the form name indicates that the
|
||||
identifiers bound by the declaration are inferred from
|
||||
@scheme[simple-factory@].
|
||||
@racket[simple-factory@].
|
||||
|
||||
Now that the identifiers in @scheme[toy-factory^] are defined, we can
|
||||
also invoke @scheme[toy-store@], which imports @scheme[toy-factory^]
|
||||
to produce @scheme[toy-store^]:
|
||||
Now that the identifiers in @racket[toy-factory^] are defined, we can
|
||||
also invoke @racket[toy-store@], which imports @racket[toy-factory^]
|
||||
to produce @racket[toy-store^]:
|
||||
|
||||
@interaction[
|
||||
#:eval toy-eval
|
||||
|
@ -190,11 +190,11 @@ to produce @scheme[toy-store^]:
|
|||
(get-inventory)
|
||||
]
|
||||
|
||||
Again, the @schemeidfont{/infer} part
|
||||
@scheme[define-values/invoke-unit/infer] determines that
|
||||
@scheme[toy-store@] imports @scheme[toy-factory^], and so it supplies
|
||||
the top-level bindings that match the names in @scheme[toy-factory^]
|
||||
as imports to @scheme[toy-store@].
|
||||
Again, the @racketidfont{/infer} part
|
||||
@racket[define-values/invoke-unit/infer] determines that
|
||||
@racket[toy-store@] imports @racket[toy-factory^], and so it supplies
|
||||
the top-level bindings that match the names in @racket[toy-factory^]
|
||||
as imports to @racket[toy-store@].
|
||||
|
||||
@; ----------------------------------------
|
||||
|
||||
|
@ -203,11 +203,11 @@ as imports to @scheme[toy-store@].
|
|||
We can make our toy economy more efficient by having toy factories
|
||||
that cooperate with stores, creating toys that do not have to be
|
||||
repainted. Instead, the toys are always created using the store's
|
||||
color, which the factory gets by importing @scheme[toy-store^]:
|
||||
color, which the factory gets by importing @racket[toy-store^]:
|
||||
|
||||
@schememod/eval[[#:file
|
||||
@racketmod/eval[[#:file
|
||||
"store-specific-factory-unit.ss"
|
||||
scheme
|
||||
racket
|
||||
|
||||
(require "toy-factory-sig.ss")]
|
||||
|
||||
|
@ -229,14 +229,14 @@ scheme
|
|||
(provide store-specific-factory@)
|
||||
]
|
||||
|
||||
To invoke @scheme[store-specific-factory@], we need
|
||||
@scheme[toy-store^] bindings to supply to the unit. But to get
|
||||
@scheme[toy-store^] bindings by invoking @scheme[toy-store@], we will
|
||||
To invoke @racket[store-specific-factory@], we need
|
||||
@racket[toy-store^] bindings to supply to the unit. But to get
|
||||
@racket[toy-store^] bindings by invoking @racket[toy-store@], we will
|
||||
need a toy factory! The unit implementations are mutually dependent,
|
||||
and we cannot invoke either before the other.
|
||||
|
||||
The solution is to @deftech{link} the units together, and then we can
|
||||
invoke the combined units. The @scheme[define-compound-unit/infer] form
|
||||
invoke the combined units. The @racket[define-compound-unit/infer] form
|
||||
links any number of units to form a combined unit. It can propagate
|
||||
imports and exports from the linked units, and it can satisfy each
|
||||
unit's imports using the exports of other linked units.
|
||||
|
@ -251,10 +251,10 @@ unit's imports using the exports of other linked units.
|
|||
toy-store@))
|
||||
]
|
||||
|
||||
The overall result above is a unit @scheme[toy-store+factory@] that
|
||||
exports both @scheme[toy-factory^] and @scheme[toy-store^]. The
|
||||
connection between @scheme[store-specific-factory@] and
|
||||
@scheme[toy-store@] is inferred from the signatures that each imports
|
||||
The overall result above is a unit @racket[toy-store+factory@] that
|
||||
exports both @racket[toy-factory^] and @racket[toy-store^]. The
|
||||
connection between @racket[store-specific-factory@] and
|
||||
@racket[toy-store@] is inferred from the signatures that each imports
|
||||
and exports.
|
||||
|
||||
This unit has no imports, so we can always invoke it:
|
||||
|
@ -271,15 +271,15 @@ This unit has no imports, so we can always invoke it:
|
|||
|
||||
@section[#:tag "firstclassunits"]{First-Class Units}
|
||||
|
||||
The @scheme[define-unit] form combines @scheme[define] with a
|
||||
@scheme[unit] form, similar to the way that @scheme[(define (f x)
|
||||
....)] combines @scheme[define] followed by an identifier with an
|
||||
implicit @scheme[lambda].
|
||||
The @racket[define-unit] form combines @racket[define] with a
|
||||
@racket[unit] form, similar to the way that @racket[(define (f x)
|
||||
....)] combines @racket[define] followed by an identifier with an
|
||||
implicit @racket[lambda].
|
||||
|
||||
Expanding the shorthand, the definition of @scheme[toy-store@] could
|
||||
Expanding the shorthand, the definition of @racket[toy-store@] could
|
||||
almost be written as
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define toy-store@
|
||||
(unit
|
||||
(import toy-factory^)
|
||||
|
@ -291,23 +291,23 @@ almost be written as
|
|||
....))
|
||||
]
|
||||
|
||||
A difference between this expansion and @scheme[define-unit] is that
|
||||
the imports and exports of @scheme[toy-store@] cannot be
|
||||
inferred. That is, besides combining @scheme[define] and
|
||||
@scheme[unit], @scheme[define-unit] attaches static information to the
|
||||
A difference between this expansion and @racket[define-unit] is that
|
||||
the imports and exports of @racket[toy-store@] cannot be
|
||||
inferred. That is, besides combining @racket[define] and
|
||||
@racket[unit], @racket[define-unit] attaches static information to the
|
||||
defined identifier so that its signature information is available
|
||||
statically to @scheme[define-values/invoke-unit/infer] and other
|
||||
statically to @racket[define-values/invoke-unit/infer] and other
|
||||
forms.
|
||||
|
||||
Despite the drawback of losing static signature information,
|
||||
@scheme[unit] can be useful in combination with other forms that work
|
||||
with first-class values. For example, we could wrap a @scheme[unit]
|
||||
that creates a toy store in a @scheme[lambda] to supply the store's
|
||||
@racket[unit] can be useful in combination with other forms that work
|
||||
with first-class values. For example, we could wrap a @racket[unit]
|
||||
that creates a toy store in a @racket[lambda] to supply the store's
|
||||
color:
|
||||
|
||||
@schememod/eval[[#:file
|
||||
@racketmod/eval[[#:file
|
||||
"toy-store-maker.ss"
|
||||
scheme
|
||||
racket
|
||||
|
||||
(require "toy-store-sig.ss"
|
||||
"toy-factory-sig.ss")]
|
||||
|
@ -340,9 +340,9 @@ scheme
|
|||
(provide toy-store@-maker)
|
||||
]
|
||||
|
||||
To invoke a unit created by @scheme[toy-store@-maker], we must use
|
||||
@scheme[define-values/invoke-unit], instead of the
|
||||
@schemeidfont{/infer} variant:
|
||||
To invoke a unit created by @racket[toy-store@-maker], we must use
|
||||
@racket[define-values/invoke-unit], instead of the
|
||||
@racketidfont{/infer} variant:
|
||||
|
||||
@interaction[
|
||||
#:eval toy-eval
|
||||
|
@ -356,17 +356,17 @@ To invoke a unit created by @scheme[toy-store@-maker], we must use
|
|||
(get-inventory)
|
||||
]
|
||||
|
||||
In the @scheme[define-values/invoke-unit] form, the @scheme[(import
|
||||
In the @racket[define-values/invoke-unit] form, the @racket[(import
|
||||
toy-factory^)] line takes bindings from the current context that match
|
||||
the names in @scheme[toy-factory^] (the ones that we created by
|
||||
invoking @scheme[simple-factory@]), and it supplies them as imports to
|
||||
@scheme[toy-store@]. The @scheme[(export toy-store^)] clause indicates
|
||||
that the unit produced by @scheme[toy-store@-maker] will export
|
||||
@scheme[toy-store^], and the names from that signature are defined
|
||||
the names in @racket[toy-factory^] (the ones that we created by
|
||||
invoking @racket[simple-factory@]), and it supplies them as imports to
|
||||
@racket[toy-store@]. The @racket[(export toy-store^)] clause indicates
|
||||
that the unit produced by @racket[toy-store@-maker] will export
|
||||
@racket[toy-store^], and the names from that signature are defined
|
||||
after invoking the unit.
|
||||
|
||||
To link a unit from @scheme[toy-store@-maker], we can use the
|
||||
@scheme[compound-unit] form:
|
||||
To link a unit from @racket[toy-store@-maker], we can use the
|
||||
@racket[compound-unit] form:
|
||||
|
||||
@interaction[
|
||||
#:eval toy-eval
|
||||
|
@ -379,27 +379,27 @@ To link a unit from @scheme[toy-store@-maker], we can use the
|
|||
[((TS : toy-store^)) toy-store@ TF])))
|
||||
]
|
||||
|
||||
This @scheme[compound-unit] form packs a lot of information into one
|
||||
place. The left-hand-side @scheme[TF] and @scheme[TS] in the
|
||||
@scheme[link] clause are binding identifiers. The identifier
|
||||
@scheme[TF] is essentially bound to the elements of
|
||||
@scheme[toy-factory^] as implemented by
|
||||
@scheme[store-specific-factory@]. The identifier @scheme[TS] is
|
||||
similarly bound to the elements of @scheme[toy-store^] as implemented
|
||||
by @scheme[toy-store@]. Meanwhile, the elements bound to @scheme[TS]
|
||||
are supplied as imports for @scheme[store-specific-factory@], since
|
||||
@scheme[TS] follows @scheme[store-specific-factory@]. The elements
|
||||
bound to @scheme[TF] are similarly supplied to
|
||||
@scheme[toy-store@]. Finally, @scheme[(export TF TS)] indicates that
|
||||
the elements bound to @scheme[TF] and @scheme[TS] are exported from
|
||||
This @racket[compound-unit] form packs a lot of information into one
|
||||
place. The left-hand-side @racket[TF] and @racket[TS] in the
|
||||
@racket[link] clause are binding identifiers. The identifier
|
||||
@racket[TF] is essentially bound to the elements of
|
||||
@racket[toy-factory^] as implemented by
|
||||
@racket[store-specific-factory@]. The identifier @racket[TS] is
|
||||
similarly bound to the elements of @racket[toy-store^] as implemented
|
||||
by @racket[toy-store@]. Meanwhile, the elements bound to @racket[TS]
|
||||
are supplied as imports for @racket[store-specific-factory@], since
|
||||
@racket[TS] follows @racket[store-specific-factory@]. The elements
|
||||
bound to @racket[TF] are similarly supplied to
|
||||
@racket[toy-store@]. Finally, @racket[(export TF TS)] indicates that
|
||||
the elements bound to @racket[TF] and @racket[TS] are exported from
|
||||
the compound unit.
|
||||
|
||||
The above @scheme[compound-unit] form uses
|
||||
@scheme[store-specific-factory@] as a first-class unit, even though
|
||||
The above @racket[compound-unit] form uses
|
||||
@racket[store-specific-factory@] as a first-class unit, even though
|
||||
its information could be inferred. Every unit can be used as a
|
||||
first-class unit, in addition to its use in inference contexts. Also,
|
||||
various forms let a programmer bridge the gap between inferred and
|
||||
first-class worlds. For example, @scheme[define-unit-binding] binds a
|
||||
first-class worlds. For example, @racket[define-unit-binding] binds a
|
||||
new identifier to the unit produced by an arbitrary expression; it
|
||||
statically associates signature information to the identifier, and it
|
||||
dynamically checks the signatures against the first-class unit
|
||||
|
@ -407,18 +407,18 @@ produced by the expression.
|
|||
|
||||
@; ----------------------------------------
|
||||
|
||||
@section{Whole-@scheme[module] Signatures and Units}
|
||||
@section{Whole-@racket[module] Signatures and Units}
|
||||
|
||||
In programs that use units, modules like @filepath{toy-factory-sig.ss}
|
||||
and @filepath{simple-factory-unit.ss} are common. The
|
||||
@scheme[scheme/signature] and @scheme[scheme/unit] module names can be
|
||||
@racket[racket/signature] and @racket[racket/unit] module names can be
|
||||
used as languages to avoid much of the boilerplate module, signature,
|
||||
and unit declaration text.
|
||||
|
||||
For example, @filepath{toy-factory-sig.ss} can be written as
|
||||
|
||||
@schememod[
|
||||
scheme/signature
|
||||
@racketmod[
|
||||
racket/signature
|
||||
|
||||
build-toys (code:comment #, @tt{(integer? -> (listof toy?))})
|
||||
repaint (code:comment #, @tt{(toy? symbol? -> toy?)})
|
||||
|
@ -426,14 +426,14 @@ toy? (code:comment #, @tt{(any/c -> boolean?)})
|
|||
toy-color (code:comment #, @tt{(toy? -> symbol?)})
|
||||
]
|
||||
|
||||
The signature @scheme[toy-factory^] is automatically provided from the
|
||||
The signature @racket[toy-factory^] is automatically provided from the
|
||||
module, inferred from the filename @filepath{toy-factory-sig.ss} by
|
||||
replacing the @filepath{-sig.ss} suffix with @schemeidfont{^}.
|
||||
replacing the @filepath{-sig.ss} suffix with @racketidfont{^}.
|
||||
|
||||
Similarly, @filepath{simple-factory-unit.ss} module can be written
|
||||
|
||||
@schememod[
|
||||
scheme/unit
|
||||
@racketmod[
|
||||
racket/unit
|
||||
|
||||
(require "toy-factory-sig.ss")
|
||||
|
||||
|
@ -452,13 +452,13 @@ scheme/unit
|
|||
(make-toy col))
|
||||
]
|
||||
|
||||
The unit @scheme[simple-factory@] is automatically provided from the
|
||||
The unit @racket[simple-factory@] is automatically provided from the
|
||||
module, inferred from the filename @filepath{simple-factory-unit.ss} by
|
||||
replacing the @filepath{-unit.ss} suffix with @schemeidfont["@"].
|
||||
replacing the @filepath{-unit.ss} suffix with @racketidfont["@"].
|
||||
|
||||
@; ----------------------------------------
|
||||
|
||||
@(interaction-eval #:eval toy-eval (require scheme/contract))
|
||||
@(interaction-eval #:eval toy-eval (require racket/contract))
|
||||
|
||||
@section{Contracts for Units}
|
||||
|
||||
|
@ -470,12 +470,12 @@ when a unit must conform to an already existing signature.
|
|||
|
||||
When contracts are added to a signature, then all units which implement
|
||||
that signature are protected by those contracts. The following version
|
||||
of the @scheme[toy-factory^] signature adds the contracts previously
|
||||
of the @racket[toy-factory^] signature adds the contracts previously
|
||||
written in comments:
|
||||
|
||||
@schememod/eval[[#:file
|
||||
@racketmod/eval[[#:file
|
||||
"contracted-toy-factory-sig.ss"
|
||||
scheme]
|
||||
racket]
|
||||
|
||||
(define-signature contracted-toy-factory^
|
||||
((contracted
|
||||
|
@ -486,12 +486,12 @@ scheme]
|
|||
|
||||
(provide contracted-toy-factory^)]
|
||||
|
||||
Now we take the previous implementation of @scheme[simple-factory@] and
|
||||
implement this version of @scheme[toy-factory^] instead:
|
||||
Now we take the previous implementation of @racket[simple-factory@] and
|
||||
implement this version of @racket[toy-factory^] instead:
|
||||
|
||||
@schememod/eval[[#:file
|
||||
@racketmod/eval[[#:file
|
||||
"contracted-simple-factory-unit.ss"
|
||||
scheme
|
||||
racket
|
||||
|
||||
(require "contracted-toy-factory-sig.ss")]
|
||||
|
||||
|
@ -530,17 +530,17 @@ causes the appropriate contract errors.
|
|||
|
||||
However, sometimes we may have a unit that must conform to an
|
||||
already existing signature that is not contracted. In this case,
|
||||
we can create a unit contract with @scheme[unit/c] or use
|
||||
the @scheme[define-unit/contract] form, which defines a unit which
|
||||
we can create a unit contract with @racket[unit/c] or use
|
||||
the @racket[define-unit/contract] form, which defines a unit which
|
||||
has been wrapped with a unit contract.
|
||||
|
||||
For example, here's a version of @scheme[toy-factory@] which still
|
||||
implements the regular @scheme[toy-factory^], but whose exports
|
||||
For example, here's a version of @racket[toy-factory@] which still
|
||||
implements the regular @racket[toy-factory^], but whose exports
|
||||
have been protected with an appropriate unit contract.
|
||||
|
||||
@schememod/eval[[#:file
|
||||
@racketmod/eval[[#:file
|
||||
"wrapped-simple-factory-unit.ss"
|
||||
scheme
|
||||
racket
|
||||
|
||||
(require "toy-factory-sig.ss")]
|
||||
|
||||
|
@ -578,32 +578,32 @@ scheme
|
|||
|
||||
@; ----------------------------------------
|
||||
|
||||
@section{@scheme[unit] versus @scheme[module]}
|
||||
@section{@racket[unit] versus @racket[module]}
|
||||
|
||||
As a form for modularity, @scheme[unit] complements @scheme[module]:
|
||||
As a form for modularity, @racket[unit] complements @racket[module]:
|
||||
|
||||
@itemize[
|
||||
|
||||
@item{The @scheme[module] form is primarily for managing a universal
|
||||
@item{The @racket[module] form is primarily for managing a universal
|
||||
namespace. For example, it allows a code fragment to refer
|
||||
specifically to the @scheme[car] operation from
|
||||
@schememodname[scheme/base]---the one that extracts the first
|
||||
specifically to the @racket[car] operation from
|
||||
@racketmodname[racket/base]---the one that extracts the first
|
||||
element of an instance of the built-in pair datatype---as
|
||||
opposed to any number of other functions with the name
|
||||
@scheme[car]. In other word, the @scheme[module] construct lets
|
||||
@racket[car]. In other word, the @racket[module] construct lets
|
||||
you refer to @emph{the} binding that you want.}
|
||||
|
||||
@item{The @scheme[unit] form is for parameterizing a code fragment
|
||||
@item{The @racket[unit] form is for parameterizing a code fragment
|
||||
with respect to most any kind of run-time value. For example,
|
||||
it allows a code fragement for work with a @scheme[car]
|
||||
it allows a code fragement for work with a @racket[car]
|
||||
function that accepts a single argument, where the specific
|
||||
function is determined later by linking the fragment to
|
||||
another. In other words, the @scheme[unit] construct lets you
|
||||
another. In other words, the @racket[unit] construct lets you
|
||||
refer to @emph{a} binding that meets some specification.}
|
||||
|
||||
]
|
||||
|
||||
The @scheme[lambda] and @scheme[class] forms, among others, also allow
|
||||
The @racket[lambda] and @racket[class] forms, among others, also allow
|
||||
paremetrization of code with respect to values that are chosen
|
||||
later. In principle, any of those could be implemented in terms of any
|
||||
of the others. In practice, each form offers certain
|
||||
|
@ -611,22 +611,22 @@ conveniences---such as allowing overriding of methods or especially
|
|||
simple application to values---that make them suitable for different
|
||||
purposes.
|
||||
|
||||
The @scheme[module] form is more fundamental than the others, in a
|
||||
The @racket[module] form is more fundamental than the others, in a
|
||||
sense. After all, a program fragment cannot reliably refer to
|
||||
@scheme[lambda], @scheme[class], or @scheme[unit] form without the
|
||||
namespace management provided by @scheme[module]. At the same time,
|
||||
@racket[lambda], @racket[class], or @racket[unit] form without the
|
||||
namespace management provided by @racket[module]. At the same time,
|
||||
because namespace management is closely related to separate expansion
|
||||
and compilation, @scheme[module] boundaries end up as
|
||||
and compilation, @racket[module] boundaries end up as
|
||||
separate-compilation boundaries in a way that prohibits mutual
|
||||
dependencies among fragments. For similar reasons, @scheme[module]
|
||||
dependencies among fragments. For similar reasons, @racket[module]
|
||||
does not separate interface from implementation.
|
||||
|
||||
Use @scheme[unit] when @scheme[module] by itself almost works, but
|
||||
Use @racket[unit] when @racket[module] by itself almost works, but
|
||||
when separately compiled pieces must refer to each other, or when you
|
||||
want a stronger separation between @defterm{interface} (i.e., the
|
||||
parts that need to be known at expansion and compilation time) and
|
||||
@defterm{implementation} (i.e., the run-time parts). More generally,
|
||||
use @scheme[unit] when you need to parameterize code over functions,
|
||||
use @racket[unit] when you need to parameterize code over functions,
|
||||
datatypes, and classes, and when the parameterized code itself
|
||||
provides definitions to be linked with other parameterized code.
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@ represent symbols and lists.
|
|||
@refdetails/gory["parse-vector"]{the syntax of vectors}
|
||||
|
||||
@examples[
|
||||
(eval:alts @#,schemevalfont{#("a" "b" "c")} #("a" "b" "c"))
|
||||
(eval:alts @#,schemevalfont{#(name (that tune))} #(name (that tune)))
|
||||
(eval:alts @#,racketvalfont{#("a" "b" "c")} #("a" "b" "c"))
|
||||
(eval:alts @#,racketvalfont{#(name (that tune))} #(name (that tune)))
|
||||
(vector-ref #("a" "b" "c") 1)
|
||||
(vector-ref #(name (that tune)) 1)
|
||||
]
|
||||
|
@ -29,10 +29,10 @@ Like strings, a vector is either mutable or immutable, and vectors
|
|||
written directly as expressions are immutable.
|
||||
|
||||
Vector can be converted to lists and vice-versa via
|
||||
@scheme[list->vector] and @scheme[vector->list]; such conversions are
|
||||
@racket[list->vector] and @racket[vector->list]; such conversions are
|
||||
particularly useful in combination with predefined procedures on
|
||||
lists. When allocating extra lists seems too expensive, consider
|
||||
using looping forms like @scheme[fold-for], which recognize vectors as
|
||||
using looping forms like @racket[fold-for], which recognize vectors as
|
||||
well as lists.
|
||||
|
||||
@examples[
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
@title[#:tag "void+undefined"]{Void and Undefined}
|
||||
|
||||
Some procedures or expression forms have no need for a result
|
||||
value. For example, the @scheme[display] procedure is called only for
|
||||
value. For example, the @racket[display] procedure is called only for
|
||||
the side-effect of writing output. In such cases the result value is
|
||||
normally a special constant that prints as @|void-const|. When the
|
||||
result of an expression is simply @|void-const|, the REPL does not
|
||||
print anything.
|
||||
|
||||
The @scheme[void] procedure takes any number of arguments and returns
|
||||
@|void-const|. (That is, the identifier @schemeidfont{void} is bound
|
||||
The @racket[void] procedure takes any number of arguments and returns
|
||||
@|void-const|. (That is, the identifier @racketidfont{void} is bound
|
||||
to a procedure that returns @|void-const|, instead of being bound
|
||||
directly to @|void-const|.)
|
||||
|
||||
|
@ -26,9 +26,9 @@ directly to @|void-const|.)
|
|||
A constant that prints as @undefined-const is used as the result of a
|
||||
reference to a local binding when the binding is not yet
|
||||
initialized. Such early references are not possible for bindings that
|
||||
correspond to procedure arguments, @scheme[let] bindings, or
|
||||
@scheme[let*] bindings; early reference requires a recursive binding
|
||||
context, such as @scheme[letrec] or local @scheme[define]s in a
|
||||
correspond to procedure arguments, @racket[let] bindings, or
|
||||
@racket[let*] bindings; early reference requires a recursive binding
|
||||
context, such as @racket[letrec] or local @racket[define]s in a
|
||||
procedure body. Also, early references to top-level and module-level
|
||||
bindings raise an exception, instead of producing
|
||||
@|undefined-const|. For these reasons, @undefined-const rarely
|
||||
|
|
|
@ -3,79 +3,80 @@
|
|||
scribble/eval
|
||||
scribble/bnf
|
||||
"guide-utils.ss"
|
||||
(for-label scheme/enter))
|
||||
(for-label racket/enter))
|
||||
|
||||
@(define piece-eval (make-base-eval))
|
||||
|
||||
@title[#:tag "intro"]{Welcome to PLT Scheme}
|
||||
@title[#:tag "intro"]{Welcome to Racket}
|
||||
|
||||
Depending on how you look at it, @bold{PLT Scheme} is
|
||||
Depending on how you look at it, @bold{Racket} is
|
||||
|
||||
@itemize[
|
||||
|
||||
@item{a @defterm{programming language}---a descendant of Scheme, which
|
||||
is a dialect of Lisp;
|
||||
@item{a @defterm{programming language}---a dialect of Lisp and a
|
||||
descendant of Scheme;
|
||||
|
||||
@margin-note{See @secref["dialects"] for more information on
|
||||
other dialects of Scheme and how they relate to PLT Scheme.}}
|
||||
other dialects of Lisp and how they relate to Racket.}}
|
||||
|
||||
@item{a @defterm{family} of programming languages---variants of
|
||||
Scheme, and more; or}
|
||||
Racket, 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.
|
||||
Where there is no room for confusion, we use simply @defterm{Racket}.
|
||||
|
||||
PLT Scheme's two main tools are
|
||||
Racket's main tools are
|
||||
|
||||
@itemize[
|
||||
|
||||
@tool["MzScheme"]{the core compiler, interpreter, and run-time
|
||||
system; and}
|
||||
@tool[@exec{racket}]{the core compiler, interpreter, and run-time system;}
|
||||
|
||||
@tool["DrScheme"]{the programming environment (which runs on top of
|
||||
MzScheme).}
|
||||
@tool["DrRacket"]{the programming environment; and}
|
||||
|
||||
@tool[@exec{raco}]{a command-line tool for executing @bold{Ra}cket
|
||||
@bold{co}mmands that install packages, build libraries, and more.}
|
||||
|
||||
]
|
||||
|
||||
Most likely, you'll want to explore PLT Scheme using DrScheme,
|
||||
Most likely, you'll want to explore the Racket language using DrRacket,
|
||||
especially at the beginning. If you prefer, you can also work with the
|
||||
command-line @exec{mzscheme} interpreter and your favorite text
|
||||
command-line @exec{racket} interpreter and your favorite text
|
||||
editor. The rest of this guide presents the language mostly
|
||||
independent of your choice of editor.
|
||||
|
||||
If you're using DrScheme, you'll need to choose the proper language,
|
||||
because DrScheme accommodates many different variants of
|
||||
Scheme. Assuming that you've never used DrScheme before, start it up,
|
||||
type the line
|
||||
If you're using DrRacket, you'll need to choose the proper language,
|
||||
because DrRacket accommodates many different variants of Racket, as
|
||||
well as other languages. Assuming that you've never used DrRacket
|
||||
before, start it up, type the line
|
||||
|
||||
@schememod[scheme]
|
||||
@racketmod[racket]
|
||||
|
||||
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 normal variant of Scheme (as opposed to the smaller
|
||||
@schememodname[scheme/base], or many other possibilities).
|
||||
in DrRacket's top text area, and then click the @onscreen{Run} button
|
||||
that's above the text area. DrRacket then understands that you mean to
|
||||
work in the normal variant of Racket (as opposed to the smaller
|
||||
@racketmodname[racket/base] or many other possibilities).
|
||||
|
||||
@margin-note{@secref["more-hash-lang"] describes some of the other
|
||||
possibilities.}
|
||||
|
||||
If you've used DrScheme before with something other than a program
|
||||
that starts @hash-lang[], DrScheme will remember the last language
|
||||
If you've used DrRacket before with something other than a program
|
||||
that starts @hash-lang[], DrRacket will remember the last language
|
||||
that you used, instead of inferring the language from the @hash-lang[]
|
||||
line. In that case, use the @menuitem["Language" "Choose Language..."]
|
||||
menu item. In the dialog that appears, select the first item,
|
||||
which is @onscreen{Module}. Put the @hash-lang[] line above in the top
|
||||
menu item. In the dialog that appears, select the first item, which
|
||||
tells DrRacket to use the language that is declared in a source
|
||||
program via @hash-lang[]. Put the @hash-lang[] line above in the top
|
||||
text area, still.
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
@section{Interacting with Scheme}
|
||||
@section{Interacting with Racket}
|
||||
|
||||
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
|
||||
DrRacket's bottom text area and the @exec{racket} command-line program
|
||||
(when started with no options) both act as a kind of calculator. You
|
||||
type a Racket expression, hit the Return key, and the answer is
|
||||
printed. In the terminology of Racket, this kind of calculator is
|
||||
called a @idefterm{read-eval-print loop} or @deftech{REPL}.
|
||||
|
||||
A number by itself is an expression, and the answer is just the
|
||||
|
@ -88,20 +89,20 @@ 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
|
||||
Racket uses parentheses to wrap larger expressions---almost any kind
|
||||
of expression, other than simple constants. For example, a function
|
||||
call is written: open parenthesis, function name, argument
|
||||
expression, and closing parenthesis. The following expression calls
|
||||
the built-in function @scheme[substring] with the arguments
|
||||
@scheme["the boy out of the country"], @scheme[4], and @scheme[7]:
|
||||
the built-in function @racket[substring] with the arguments
|
||||
@racket["the boy out of the country"], @racket[4], and @racket[7]:
|
||||
|
||||
@interaction[(substring "the boy out of the country" 4 7)]
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
@section{Definitions and Interactions}
|
||||
|
||||
You can define your own functions that work like @scheme[substring] by
|
||||
using the @scheme[define] form, like this:
|
||||
You can define your own functions that work like @racket[substring] by
|
||||
using the @racket[define] form, like this:
|
||||
|
||||
@def+int[
|
||||
#:eval piece-eval
|
||||
|
@ -111,48 +112,48 @@ using the @scheme[define] form, like this:
|
|||
(extract "the country out of the boy")
|
||||
]
|
||||
|
||||
Although you can evaluate the @scheme[define] form in the @tech{REPL},
|
||||
Although you can evaluate the @racket[define] form in the @tech{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
|
||||
use later. So, in DrRacket, you'd normally put the definition in the
|
||||
top text area---called the @deftech{definitions area}---along with the
|
||||
@hash-lang[] prefix:
|
||||
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
code:blank
|
||||
(define (extract str)
|
||||
(substring str 4 7))
|
||||
]
|
||||
|
||||
If calling @scheme[(extract "the boy")] is part of the main action of
|
||||
If calling @racket[(extract "the boy")] is part of the main action of
|
||||
your program, that would go in the @tech{definitions area}, too. But
|
||||
if it was just an example expression that you were using to explore
|
||||
@scheme[extract], then you'd more likely leave the @tech{definitions
|
||||
@racket[extract], then you'd more likely leave the @tech{definitions
|
||||
area} as above, click @onscreen{Run}, and then evaluate
|
||||
@scheme[(extract "the boy")] in the @tech{REPL}.
|
||||
@racket[(extract "the boy")] in the @tech{REPL}.
|
||||
|
||||
With @exec{mzscheme}, you'd save the above text in a file using your
|
||||
favorite editor. If you save it as @filepath{extract.ss}, then after starting
|
||||
@exec{mzscheme} in the same directory, you'd evaluate the following
|
||||
With @exec{racket}, you'd save the above text in a file using your
|
||||
favorite editor. If you save it as @filepath{extract.rkt}, then after starting
|
||||
@exec{racket} in the same directory, you'd evaluate the following
|
||||
sequence:
|
||||
|
||||
@interaction[
|
||||
#:eval piece-eval
|
||||
(eval:alts (enter! "extract.ss") (void))
|
||||
(eval:alts (enter! "extract.rkt") (void))
|
||||
(extract "the gal out of the city")
|
||||
]
|
||||
|
||||
The @scheme[enter!] form both loads the code and switches the
|
||||
evaluation context to the inside of the module, just like DrScheme's
|
||||
The @racket[enter!] form both loads the code and switches the
|
||||
evaluation context to the inside of the module, just like DrRacket's
|
||||
@onscreen{Run} button.
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
@section{Creating Executables}
|
||||
|
||||
If your file (or @tech{definitions area} in DrScheme) contains
|
||||
If your file (or @tech{definitions area} in DrRacket) contains
|
||||
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
|
||||
(define (extract str)
|
||||
(substring str 4 7))
|
||||
|
@ -166,14 +167,13 @@ options:
|
|||
|
||||
@itemize[
|
||||
|
||||
@item{In DrScheme, you can select the @menuitem["Scheme" "Create
|
||||
@item{In DrRacket, you can select the @menuitem["Racket" "Create
|
||||
Executable..."] menu item.}
|
||||
|
||||
@item{From a command-line prompt, run @exec{mzc --exe
|
||||
@nonterm{dest-filename} @nonterm{src-filename}}, where
|
||||
@nonterm{src-filename} contains the program. See @secref[#:doc
|
||||
'(lib "scribblings/mzc/mzc.scrbl") "exe"] for more
|
||||
information.}
|
||||
@item{From a command-line prompt, run @exec{raco exe
|
||||
@nonterm{src-filename}}, where @nonterm{src-filename} contains
|
||||
the program. See @secref[#:doc '(lib
|
||||
"scribblings/mzc/mzc.scrbl") "exe"] for more information.}
|
||||
|
||||
@item{With Unix or Mac OS X, you can turn the program file into an
|
||||
executable script by inserting the line
|
||||
|
@ -181,32 +181,32 @@ options:
|
|||
@margin-note{See @secref["scripts"] for more information on
|
||||
script files.}
|
||||
|
||||
@verbatim[#:indent 2]{#! /usr/bin/env mzscheme}
|
||||
@verbatim[#:indent 2]{#! /usr/bin/env racket}
|
||||
|
||||
at the very beginning of the file. Also, change the file
|
||||
permissions to executable using @exec{chmod +x
|
||||
@nonterm{filename}} on the command line.
|
||||
|
||||
The script works as long as @exec{mzscheme} is in the user's
|
||||
The script works as long as @exec{racket} is in the user's
|
||||
executable search path. Alternately, use a full path to
|
||||
@exec{mzscheme} after @tt{#!} (with a space between @tt{#!}
|
||||
@exec{racket} after @tt{#!} (with a space between @tt{#!}
|
||||
and the path), in which case the user's executable search path
|
||||
does not matter.}
|
||||
|
||||
]
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
@section[#:tag "use-module"]{A Note to Readers with Scheme/Lisp Experience}
|
||||
@section[#:tag "use-module"]{A Note to Readers with Lisp/Scheme Experience}
|
||||
|
||||
If you already know something about Scheme or Lisp, you might be
|
||||
If you already know something about Racket or Lisp, you might be
|
||||
tempted to put just
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define (extract str)
|
||||
(substring str 4 7))
|
||||
]
|
||||
|
||||
into @filepath{extract.scm} and run @exec{mzscheme} with
|
||||
into @filepath{extract.scm} and run @exec{racket} with
|
||||
|
||||
@interaction[
|
||||
#:eval piece-eval
|
||||
|
@ -214,18 +214,18 @@ into @filepath{extract.scm} and run @exec{mzscheme} with
|
|||
(extract "the dog out")
|
||||
]
|
||||
|
||||
That will work, because @exec{mzscheme} is willing to imitate a
|
||||
That will work, because @exec{racket} is willing to imitate a
|
||||
traditional Scheme environment, but we strongly recommend against using
|
||||
@scheme[load] or writing programs outside of a module.
|
||||
@racket[load] or writing programs outside of a module.
|
||||
|
||||
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 specific to @exec{mzscheme}; they're
|
||||
programs. The problems are not specific to @exec{racket}; they're
|
||||
fundamental limitations of the traditional top-level environment,
|
||||
which Scheme and Lisp implementations have historically fought with ad
|
||||
hoc command-line flags, compiler directives, and build tools. The
|
||||
module system is to designed to avoid the problems, so start with
|
||||
@hash-lang[], and you'll be happier with PLT Scheme in the long run.
|
||||
@hash-lang[], and you'll be happier with Racket in the long run.
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
@title[#:tag "define-struct"]{Defining Structure Types: @racket[struct]}
|
||||
|
||||
@guideintro["define-struct"]{@racket[define-struct]}
|
||||
@guideintro["define-struct"]{@racket[struct]}
|
||||
|
||||
@defform/subs[(struct id maybe-super (field ...)
|
||||
struct-option ...)
|
||||
|
|
|
@ -2304,6 +2304,8 @@ expression).
|
|||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "quasiquote"]{Quasiquoting: @racket[quasiquote], @racket[unquote], and @racket[unquote-splicing]}
|
||||
|
||||
@guideintro["qq"]{@racket[quasiquote]}
|
||||
|
||||
@defform[(quasiquote datum)]{
|
||||
|
||||
The same as @racket[(quote datum)] if @racket[datum] does not include
|
||||
|
|
Loading…
Reference in New Issue
Block a user