schemeblock improvements and reference-manual work
svn: r6468
This commit is contained in:
parent
1489f1b870
commit
d2f0b1756c
|
@ -175,7 +175,10 @@
|
|||
[(sf) `((b (font ([size "-1"][face "Helvetica"]) ,@(super render-element e part ht))))]
|
||||
[(subscript) `((sub ,@(super render-element e part ht)))]
|
||||
[(superscript) `((sup ,@(super render-element e part ht)))]
|
||||
[(hspace) `((tt ,@(map (lambda (c) 'nbsp) (string->list (content->string (element-content e))))))]
|
||||
[(hspace) `((tt ,@(let ([str (content->string (element-content e))])
|
||||
(if (= 1 (string-length str))
|
||||
'(" ")
|
||||
(map (lambda (c) 'nbsp) (string->list str))))))]
|
||||
[else (error 'html-render "unrecognized style symbol: ~e" style)])]
|
||||
[(string? style)
|
||||
`((span ([class ,style]) ,@(super render-element e part ht)))]
|
||||
|
@ -195,15 +198,22 @@
|
|||
[(at-left) '((align "left"))]
|
||||
[else null]))
|
||||
,@(map (lambda (flows)
|
||||
`(tr ,@(map (lambda (d a)
|
||||
`(td ,@(case a
|
||||
`(tr ,@(map (lambda (d a va)
|
||||
`(td (,@(case a
|
||||
[(#f) null]
|
||||
[(right) '(((align "right")))]
|
||||
[(left) '(((align "left")))])
|
||||
[(right) '((align "right"))]
|
||||
[(left) '((align "left"))])
|
||||
,@(case va
|
||||
[(#f) null]
|
||||
[(top) '((valign "top"))]
|
||||
[(bottom) '((valign "bottom"))]))
|
||||
,@(render-flow d part ht)))
|
||||
flows
|
||||
(cdr (or (and (list? (table-style t))
|
||||
(assoc 'alignment (or (table-style t) null)))
|
||||
(cons #f (map (lambda (x) #f) flows))))
|
||||
(cdr (or (and (list? (table-style t))
|
||||
(assoc 'valignment (or (table-style t) null)))
|
||||
(cons #f (map (lambda (x) #f) flows)))))))
|
||||
(table-flowss t)))))
|
||||
|
||||
|
|
|
@ -34,7 +34,8 @@
|
|||
quote quasiquote unquote unquote-splicing
|
||||
syntax quasisyntax unsyntax unsyntax-splicing
|
||||
for/fold for/list for*/list for for/and for/or for* for*/or for*/and for*/fold
|
||||
for-values for*/list-values for/first for/last)))
|
||||
for-values for*/list-values for/first for/last
|
||||
set!)))
|
||||
(define current-variable-list
|
||||
(make-parameter null))
|
||||
|
||||
|
@ -50,14 +51,20 @@
|
|||
[init-col (or (syntax-column first) 0)]
|
||||
[src-col init-col]
|
||||
[dest-col 0]
|
||||
[highlight? #f]
|
||||
[col-map (make-hash-table 'equal)]
|
||||
[next-col-map (make-hash-table 'equal)]
|
||||
[line (or (syntax-line first) 0)])
|
||||
(define (finish-line!)
|
||||
(when multi-line?
|
||||
(set! docs (cons (make-flow (list (make-paragraph (reverse content))))
|
||||
docs))
|
||||
(set! content null)))
|
||||
(define (out v cls)
|
||||
(define out
|
||||
(case-lambda
|
||||
[(v cls)
|
||||
(out v cls (if (string? v) (string-length v) 1))]
|
||||
[(v cls len)
|
||||
(unless (equal? v "")
|
||||
(if (equal? v "\n")
|
||||
(if multi-line?
|
||||
|
@ -66,29 +73,35 @@
|
|||
(out prefix cls))
|
||||
(out " " cls))
|
||||
(begin
|
||||
(set! content (cons (if color?
|
||||
(set! content (cons ((if highlight?
|
||||
(lambda (c)
|
||||
(make-element "highlighted" (list c)))
|
||||
values)
|
||||
(if color?
|
||||
(make-element cls (list v))
|
||||
(make-element 'tt (list v)))
|
||||
(make-element 'tt (list v))))
|
||||
content))
|
||||
(set! dest-col (+ dest-col (if (string? v) (string-length v) 1)))))))
|
||||
(set! dest-col (+ dest-col len)))))]))
|
||||
(define advance
|
||||
(case-lambda
|
||||
[(c init-line! delta)
|
||||
(let ([c (+ delta (syntax-column c))]
|
||||
[l (syntax-line c)]
|
||||
[span (syntax-span c)])
|
||||
(when (and l (l . > . line))
|
||||
[l (syntax-line c)])
|
||||
(let ([new-line? (and l (l . > . line))])
|
||||
(when new-line?
|
||||
(out "\n" no-color)
|
||||
(set! line l)
|
||||
(set! col-map next-col-map)
|
||||
(set! next-col-map (make-hash-table 'equal))
|
||||
(init-line!))
|
||||
(when c
|
||||
(let ([d-col (hash-table-get col-map src-col src-col)])
|
||||
(let ([amt (+ (- c src-col) (- d-col dest-col))])
|
||||
(let ([d-col (hash-table-get col-map c (+ dest-col (- c src-col)))])
|
||||
(let ([amt (- d-col dest-col)])
|
||||
(when (positive? amt)
|
||||
(let ([old-dest-col dest-col])
|
||||
(out (make-element 'hspace (list (make-string amt #\space))) #f)
|
||||
(set! dest-col (+ old-dest-col amt))))))
|
||||
(set! src-col (+ c (or span 1)))))]
|
||||
(set! src-col c)
|
||||
(hash-table-put! next-col-map src-col dest-col)))]
|
||||
[(c init-line!) (advance c init-line! 0)]))
|
||||
(define (convert-infix c quote-depth)
|
||||
(let ([l (syntax->list c)])
|
||||
|
@ -167,21 +180,36 @@
|
|||
l))]
|
||||
[(and (pair? (syntax-e c))
|
||||
(eq? (syntax-e (car (syntax-e c))) 'code:line))
|
||||
(let ([l (cdr (syntax->list c))])
|
||||
(for-each (loop init-line! quote-depth)
|
||||
(cdr (syntax->list c)))]
|
||||
l))]
|
||||
[(and (pair? (syntax-e c))
|
||||
(eq? (syntax-e (car (syntax-e c))) 'code:hilite))
|
||||
(let ([l (syntax->list c)]
|
||||
[h? highlight?])
|
||||
(unless (and l (= 2 (length l)))
|
||||
(error "bad code:redex: ~e" (syntax-object->datum c)))
|
||||
(advance c init-line!)
|
||||
(set! src-col (syntax-column (cadr l)))
|
||||
(hash-table-put! next-col-map src-col dest-col)
|
||||
(set! highlight? #t)
|
||||
((loop init-line! quote-depth) (cadr l))
|
||||
(set! highlight? h?)
|
||||
(set! src-col (add1 src-col)))]
|
||||
[(and (pair? (syntax-e c))
|
||||
(eq? (syntax-e (car (syntax-e c))) 'code:quote))
|
||||
(advance c init-line!)
|
||||
(out "(" (if (positive? quote-depth) value-color paren-color))
|
||||
(set! src-col (+ src-col 1))
|
||||
(hash-table-put! col-map src-col dest-col)
|
||||
(hash-table-put! next-col-map src-col dest-col)
|
||||
((loop init-line! quote-depth)
|
||||
(datum->syntax-object #'here 'quote (car (syntax-e c))))
|
||||
(for-each (loop init-line! (add1 quote-depth))
|
||||
(cdr (syntax->list c)))
|
||||
(out ")" (if (positive? quote-depth) value-color paren-color))
|
||||
(set! src-col (+ src-col 1))
|
||||
(hash-table-put! col-map src-col dest-col)]
|
||||
#;
|
||||
(hash-table-put! next-col-map src-col dest-col)]
|
||||
[(and (pair? (syntax-e c))
|
||||
(memq (syntax-e (car (syntax-e c)))
|
||||
'(quote quasiquote unquote unquote-splicing
|
||||
|
@ -200,13 +228,14 @@
|
|||
meta-color))
|
||||
(let ([i (cadr (syntax->list c))])
|
||||
(set! src-col (or (syntax-column i) src-col))
|
||||
(hash-table-put! col-map src-col dest-col)
|
||||
(hash-table-put! next-col-map src-col dest-col)
|
||||
((loop init-line! (+ quote-depth quote-delta)) i)))]
|
||||
[(and (pair? (syntax-e c))
|
||||
(convert-infix c quote-depth))
|
||||
=> (lambda (converted)
|
||||
((loop init-line! quote-depth) converted))]
|
||||
[(or (pair? (syntax-e c))
|
||||
(null? (syntax-e c))
|
||||
(vector? (syntax-e c)))
|
||||
(let* ([sh (or (syntax-property c 'paren-shape)
|
||||
#\()]
|
||||
|
@ -220,14 +249,20 @@
|
|||
paren-color))])
|
||||
(advance c init-line!)
|
||||
(when (vector? (syntax-e c))
|
||||
(out (format "#~a" (vector-length (syntax-e c))) p-color))
|
||||
(let ([vec (syntax-e c)])
|
||||
(out (format "#~a" (vector-length vec)) p-color)
|
||||
(if (zero? (vector-length vec))
|
||||
(set! src-col (+ src-col (- (syntax-span c) 2)))
|
||||
(set! src-col (+ src-col (- (syntax-column (vector-ref vec 0))
|
||||
(syntax-column c)
|
||||
1))))))
|
||||
(out (case sh
|
||||
[(#\[ #\?) "["]
|
||||
[(#\{) "{"]
|
||||
[else "("])
|
||||
p-color)
|
||||
(set! src-col (+ src-col 1))
|
||||
(hash-table-put! col-map src-col dest-col)
|
||||
(hash-table-put! next-col-map src-col dest-col)
|
||||
(let lloop ([l (if (vector? (syntax-e c))
|
||||
(vector->short-list (syntax-e c) syntax-e)
|
||||
c)])
|
||||
|
@ -246,7 +281,7 @@
|
|||
(advance l init-line! -2)
|
||||
(out ". " (if (positive? quote-depth) value-color paren-color))
|
||||
(set! src-col (+ src-col 3))
|
||||
(hash-table-put! col-map src-col dest-col)
|
||||
(hash-table-put! next-col-map src-col dest-col)
|
||||
((loop init-line! quote-depth) l)]))
|
||||
(out (case sh
|
||||
[(#\[ #\?) "]"]
|
||||
|
@ -254,12 +289,13 @@
|
|||
[else ")"])
|
||||
p-color)
|
||||
(set! src-col (+ src-col 1))
|
||||
(hash-table-put! col-map src-col dest-col))]
|
||||
#;
|
||||
(hash-table-put! next-col-map src-col dest-col))]
|
||||
[(box? (syntax-e c))
|
||||
(advance c init-line!)
|
||||
(out "#&" value-color)
|
||||
(set! src-col (+ src-col 2))
|
||||
(hash-table-put! col-map src-col dest-col)
|
||||
(hash-table-put! next-col-map src-col dest-col)
|
||||
((loop init-line! +inf.0) (unbox (syntax-e c)))]
|
||||
[(hash-table? (syntax-e c))
|
||||
(advance c init-line!)
|
||||
|
@ -269,7 +305,7 @@
|
|||
"#hasheq")
|
||||
value-color)
|
||||
(set! src-col (+ src-col 5 (if equal-table? 2 0)))
|
||||
(hash-table-put! col-map src-col dest-col)
|
||||
(hash-table-put! next-col-map src-col dest-col)
|
||||
((loop init-line! +inf.0)
|
||||
(syntax-ize (hash-table-map (syntax-e c) cons)
|
||||
(syntax-column c))))]
|
||||
|
@ -323,10 +359,14 @@
|
|||
variable-color]
|
||||
[it? variable-color]
|
||||
[else symbol-color])]
|
||||
[else paren-color])))
|
||||
(hash-table-put! col-map src-col dest-col))])))
|
||||
(hash-table-put! col-map src-col dest-col)
|
||||
[else paren-color])
|
||||
(string-length s)))
|
||||
(set! src-col (+ src-col (or (syntax-span c) 1)))
|
||||
#;
|
||||
(hash-table-put! next-col-map src-col dest-col))])))
|
||||
(out prefix1 #f)
|
||||
(set! dest-col 0)
|
||||
(hash-table-put! next-col-map init-col dest-col)
|
||||
((loop (lambda () (set! src-col init-col) (set! dest-col 0)) 0) c)
|
||||
(unless (null? content)
|
||||
(finish-line!))
|
||||
|
|
|
@ -144,11 +144,19 @@
|
|||
}
|
||||
*/
|
||||
|
||||
.ghost {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.scheme em {
|
||||
color: black;
|
||||
font-family: serif;
|
||||
}
|
||||
|
||||
.highlighted {
|
||||
background-color: #ddddff;
|
||||
}
|
||||
|
||||
.schemeinput {
|
||||
color: brown;
|
||||
background-color: #eeeeee;
|
||||
|
|
521
collects/scribblings/reference/model.scrbl
Normal file
521
collects/scribblings/reference/model.scrbl
Normal file
|
@ -0,0 +1,521 @@
|
|||
#reader(lib "docreader.ss" "scribble")
|
||||
@require[(lib "struct.ss" "scribble")]
|
||||
@require-for-syntax[mzscheme]
|
||||
@require["mz.ss"]
|
||||
@require["prog-steps.ss"]
|
||||
|
||||
@define[reduces (make-element #f (list 'rarr))]
|
||||
@define[rspace (make-element "ghost" (list 'rarr))]
|
||||
|
||||
@define[*redex (lambda (c)
|
||||
(make-element "highlighted" (list c)))]
|
||||
@define-syntax[redex (syntax-rules ()
|
||||
[(_ a) (*redex (scheme a))])]
|
||||
|
||||
|
||||
@define[hole (make-element #f (list "[]"))]
|
||||
@define[(*sub c e) (make-element #f (list c "[" e "]"))]
|
||||
@define[langle (make-element 'tt (list "<"))]
|
||||
@define[rangle (make-element 'tt (list ">"))]
|
||||
@define[comma (make-element 'tt (list ", "))]
|
||||
@define-syntax[sub (syntax-rules ()
|
||||
[(_ a b) (*sub (scheme a) (scheme b))])]
|
||||
@define[(*state c e) (make-element #f (list langle c comma e rangle))]
|
||||
@define-syntax[state (syntax-rules ()
|
||||
[(_ a b) (*state (scheme a) (scheme b))])]
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@title{Language Model}
|
||||
|
||||
Scheme evaluation can be viewed as the simplification of expressions
|
||||
to obtain values. For example, just as an elementary-school student
|
||||
simplifies
|
||||
|
||||
@verbatim{ 1 + 1 = 2}
|
||||
|
||||
Scheme evaluation simplifies
|
||||
|
||||
@schemeblock[
|
||||
(+ 1 1) #, @reduces 2
|
||||
]
|
||||
|
||||
The arrow @reduces above replaces the more traditional @tt{=} to
|
||||
emphasize that evaluation proceeds in a particular direction towards
|
||||
simplier expressions. In particular, a @defterm{value} is an
|
||||
expression that evaluation simplifies no further, such as the number
|
||||
@scheme[2].
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Sub-expression Evaluation}
|
||||
|
||||
Some simplifications require more than one step. For example:
|
||||
|
||||
@schemeblock[
|
||||
(- 4 #,(redex (+ 1 1))) #,reduces #,(redex (- 4 2)) #,reduces 2
|
||||
]
|
||||
|
||||
An expression that is not a value can always be partitioned into two
|
||||
parts: a @defterm{redex}, which is the part that changed in a
|
||||
single-step simplification (show in blue), and the
|
||||
@defterm{continuation}, which is the surrounding expression
|
||||
context. In @scheme[(- 4 (+ 1 1))], the redex is @scheme[(+ 1 1)], and
|
||||
the continuation is @scheme[(- 4 #, @hole)], where @hole takes the
|
||||
place of the redex. That is, the continuation says how to ``continue''
|
||||
after the redex is reduced to a value.
|
||||
|
||||
Before some things can be evaluated, some sub-expressions must be
|
||||
evaluated; for example, in the application @scheme[(- 4 (+ 1 1))], the
|
||||
application of @scheme[-] cannot be reduced until the sub-expression
|
||||
@scheme[(+ 1 1)] is reduced.
|
||||
|
||||
Thus, the specification of each syntactic form specifies how (some of)
|
||||
it's sub-expressions are evaluated, and then how the results are
|
||||
combined to reduce the form away.
|
||||
|
||||
The @defterm{dynamic extent} of an expression is the sequence of
|
||||
evaluation steps during which an expression contains the redex.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Tail Position}
|
||||
|
||||
An expression @scheme[_expr1] is in @defterm{tail position} with
|
||||
respect to an enclosing expression @scheme[_expr2] if, whenever
|
||||
@scheme[_expr1] becomes a redex, its continuation is the same as was
|
||||
the enclosing @scheme[_expr2]'s continuation.
|
||||
|
||||
For example, the @scheme[(+ 1 1)] expression is @italic{not} in tail
|
||||
position with respect to @scheme[(- 4 (+ 1 1))]. To illustrate, we use
|
||||
the notation @sub[_C _expr] to mean the expression that is produced by
|
||||
substituing @scheme[_expr] in place of @hole in the continuation
|
||||
@scheme[_C]:
|
||||
|
||||
@schemeblock[
|
||||
#, @sub[_C (- 4 (+ 1 1))] #, @reduces #, @sub[_C (- 4 2)]
|
||||
]
|
||||
|
||||
In this case, the continuation for reducing @scheme[(+ 1 1)] is @sub[_C (+
|
||||
4 #, @hole)], not just @scheme[_C].
|
||||
|
||||
In contrast, @scheme[(+ 1 1)] is in tail position with respect to
|
||||
@scheme[(if (zero? 0) (+ 1 1) 3)], because, for any continuation @scheme[_C],
|
||||
|
||||
@schemeblock[
|
||||
#, @sub[_C (if (zero? 0) (+ 1 1) 3)] #, @reduces #, @sub[_C (if #t (+ 1 1) 3)] #, @reduces #, @sub[_C (+ 1 1)]
|
||||
]
|
||||
|
||||
The steps in this reduction sequence are driven by the definition of
|
||||
@scheme[if], and they do not depend on the continuation
|
||||
@scheme[_C]. The ``then'' branch of an @scheme[if] form is always in
|
||||
tail position with respect to the @scheme[if] form. Due to a similar
|
||||
reduction rule for @scheme[if] and @scheme[#f], the ``else'' branch of
|
||||
an @scheme[if] form is also in tail position.
|
||||
|
||||
Tail-position specifications provide a guarantee about the asymtotic
|
||||
space consumption of a computation. In general, the specification of
|
||||
tail positions goes with each syntactic form, like @scheme[if].
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Multiple Return Values}
|
||||
|
||||
A Scheme expression can evaluate to @defterm{multiple values}, in the
|
||||
same way that a procedure can accept multiple arguments.
|
||||
|
||||
Most continuations expect a particular number of result values.
|
||||
Indeed, most continuations, such as @scheme[(+ #, @hole 1)] expect a
|
||||
single value. The continuation @scheme[(let-values ([(x y) #, @hole])
|
||||
_expr)] expects two result values; the first result replaces
|
||||
@scheme[x] in the body @scheme[_expr], and the second replaces
|
||||
@scheme[y] in @scheme[_expr]. The continuation @scheme[(begin #, @hole
|
||||
(+ 1 2))] accepts any number of result values, because it ignores the
|
||||
result(s).
|
||||
|
||||
In general, the specification of a syntactic form inidicates the
|
||||
number of values that it produces and the number that it expects from
|
||||
each of its sub-expression. In addtion, some procedures (notably
|
||||
@scheme[values]) produce multiple values, and some procedures (notably
|
||||
@scheme[call-with-values]) create continuations internally that accept
|
||||
a certain number of values.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Top-level and Module Bindings}
|
||||
|
||||
Given
|
||||
|
||||
@verbatim{ x = 10}
|
||||
|
||||
then an algebra student simplifies @tt{x + 1} as follows:
|
||||
|
||||
@verbatim{ x + 1 = 10 + 1 = 11}
|
||||
|
||||
Scheme works much the same way, in that a set of top-level bindings
|
||||
are available for substitutions on demand during evaluation. For
|
||||
example, given
|
||||
|
||||
@schemeblock[
|
||||
(define x 10)
|
||||
]
|
||||
|
||||
then
|
||||
|
||||
@schemeblock[
|
||||
#,(redex (+ x 1)) #,reduces #,(redex (+ 10 1)) #,reduces 11
|
||||
]
|
||||
|
||||
In Scheme, the way definitions appear is just as important as the way
|
||||
that they are used. Scheme evaluation thus keeps track of both
|
||||
definitions and the current expression, and it extends the set of
|
||||
definitions in response to evaluating forms such as @scheme[define].
|
||||
|
||||
Each evaluation step, then, takes the current set of definitions and
|
||||
program to a new set of definitions and program. Before a
|
||||
@scheme[define] can be moved into the set of definitions, its
|
||||
right-hand expression must be reduced to a value.
|
||||
|
||||
@prog-steps/no-obj[
|
||||
[{}
|
||||
(begin (define x (code:hilite (+ 9 1))) (+ x 1))]
|
||||
[{}
|
||||
(begin (code:hilite (define x 10)) (+ x 1))]
|
||||
[{(define x 10)}
|
||||
(code:hilite (begin #,(void-const) (+ x 1)))]
|
||||
[{(define x 10)}
|
||||
(+ (code:hilite x) 1)]
|
||||
[{(define x 10)}
|
||||
(code:hilite (+ 10 1))]
|
||||
[{(define x 10)}
|
||||
11]
|
||||
]
|
||||
|
||||
Most definitions in PLT Scheme are in modules. In terms of evaluation,
|
||||
a module is simply a prefix on a defined name, so that different
|
||||
modules can define the name.
|
||||
|
||||
Using @scheme[set!], a program can change the value associated with an
|
||||
existing top-level binding:
|
||||
|
||||
@prog-steps/no-obj[
|
||||
[{(define x 10)}
|
||||
(begin (code:hilite (set! x 8)) x)]
|
||||
[{(define x 8)}
|
||||
(code:hilite (begin #,(void-const) x))]
|
||||
[{(define x 8)}
|
||||
(code:hilite x)]
|
||||
[{(define x 8)}
|
||||
8]
|
||||
]
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Objects and Imperative Update}
|
||||
|
||||
In addition to @scheme[set!] for imperative update of top-level
|
||||
bindings, various procedures enable the modification of elements
|
||||
within a compound data structure. For example, @scheme[vector-set!]
|
||||
modifies the content of a vector.
|
||||
|
||||
To allow such modifications to data, we must distingiush between
|
||||
values, which are the results of expressions, and @defterm{objects},
|
||||
which hold the data referenced by a value.
|
||||
|
||||
A few kinds of objects can serve directly as values, including
|
||||
booleans, @void-const[], and small exact integers. More generally,
|
||||
however, a value is a reference to an object. For example, a value can
|
||||
be a reference to a particular vector that currently holds the value
|
||||
@scheme[10] in its first slot. If an object is modified, then the
|
||||
modification is visible through all copies of the value that reference
|
||||
the same object.
|
||||
|
||||
In the evaluation model, a set of objects must be carried along with
|
||||
each step in evaluation, just like the definition set. Operations that
|
||||
create objects, such as @scheme[vector], add to the set of objects:
|
||||
|
||||
@prog-steps[
|
||||
[{}
|
||||
{}
|
||||
(begin (define x (code:hilite (vector 10 20)))
|
||||
(define y x)
|
||||
(vector-set! x 0 11)
|
||||
(vector-ref y 0))]
|
||||
[{(define <o1> #(10 20))}
|
||||
{}
|
||||
(begin (code:hilite (define x <o1>))
|
||||
(define y x)
|
||||
(vector-set! x 0 11)
|
||||
(vector-ref y 0))]
|
||||
[{(define <o1> #(10 20))}
|
||||
{(define x <o1>)}
|
||||
(code:hilite (begin #,(void-const)
|
||||
(define y x)
|
||||
(vector-set! x 0 11)
|
||||
(vector-ref y 0)))]
|
||||
[{(define <o1> #(10 20))}
|
||||
{(define x <o1>)}
|
||||
(begin (define y (code:hilite x))
|
||||
(vector-set! x 0 11)
|
||||
(vector-ref y 0))]
|
||||
[{(define <o1> #(10 20))}
|
||||
{(define x <o1>)}
|
||||
(begin (code:hilite (define y <o1>))
|
||||
(vector-set! x 0 11)
|
||||
(vector-ref y 0))]
|
||||
[{(define <o1> #(10 20))}
|
||||
{(define x <o1>)
|
||||
(define y <o1>)}
|
||||
(code:hilite (begin #,(void-const)
|
||||
(vector-set! x 0 11)
|
||||
(vector-ref y 0)))]
|
||||
[{(define <o1> #(10 20))}
|
||||
{(define x <o1>)
|
||||
(define y <o1>)}
|
||||
(begin (vector-set! (code:hilite x) 0 11)
|
||||
(vector-ref y 0))]
|
||||
[{(define <o1> #(10 20))}
|
||||
{(define x <o1>)
|
||||
(define y <o1>)}
|
||||
(begin (code:hilite (vector-set! <o1> 0 11))
|
||||
(vector-ref y 0))]
|
||||
[{(define <o1> #(11 20))}
|
||||
{(define x <o1>)
|
||||
(define y <o1>)}
|
||||
(code:hilite (begin #,(void-const)
|
||||
(vector-ref y 0)))]
|
||||
[{(define <o1> #(11 20))}
|
||||
{(define x <o1>)
|
||||
(define y <o1>)}
|
||||
(vector-ref (code:hilite y) 0)]
|
||||
[{(define <o1> #(11 20))}
|
||||
{(define x <o1>)
|
||||
(define y <o1>)}
|
||||
(code:hilite (vector-ref <o1> 0))]
|
||||
[{(define <o1> #(11 20))}
|
||||
{(define x <o1>)
|
||||
(define y <o1>)}
|
||||
11]
|
||||
]
|
||||
|
||||
The distinction between a top-level binding is an object reference is
|
||||
crucial. A top-level binding is not a value; each time a binding
|
||||
expression is evaluated, the value is extracted from the current set
|
||||
of definitions. An object reference, in contrast is a value, and
|
||||
therefore needs no further evaluation. The model evaluation steps
|
||||
above use angle-bracketed @scheme[<o1>] for an object reference to
|
||||
distinguish it from a variable name.
|
||||
|
||||
A direct object reference can never appear in a text-based source
|
||||
program. A program representation created with
|
||||
@scheme[datum->syntax-object], however, can embed direct references to
|
||||
existing objects.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Object Identity and Comparisons}
|
||||
|
||||
The @scheme[eq?] operator compares two values, returning @scheme[#t]
|
||||
when the values refer to the same object. This form of equality is
|
||||
suitabel for comparing objects that support imperative update (e.g.,
|
||||
to determine that the effect of modifying an object through one
|
||||
reference is visible through another reference). Also, an @scheme[eq?]
|
||||
test evaluates quickly, and @scheme[eq?]-based hashing is more
|
||||
lightweight than @scheme[equal?]-based hashing in hash tables.
|
||||
|
||||
In some cases, however, @scheme[eq?] is unsuitable as a comparison
|
||||
operator, because the generation of objects is not clearly defined. In
|
||||
particular, two applications of @scheme[+] to the same two exact
|
||||
integers may or may not produce results that are @scheme[eq?],
|
||||
although the results are always @scheme[equal?]. Similarly, evaluation
|
||||
of a @scheme[lambda] form typically generates a new procedure object,
|
||||
but it may re-use a procedure object previously generated by the same
|
||||
source @scheme[lambda] form.
|
||||
|
||||
The behavior of a datatype with respect to @scheme[eq?] is generally
|
||||
specified with the datatype and its associated procedures.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Garbage Collection}
|
||||
|
||||
In the program state
|
||||
|
||||
@prog-steps[
|
||||
[{(define <o1> #(10 20))
|
||||
(define <o2> #(0))}
|
||||
{(define x <o1>)}
|
||||
(+ 1 x)]
|
||||
]
|
||||
|
||||
evaluation cannot depend on @scheme[<o2>], because it is not part of
|
||||
the program to evaluate, and it is not referenced by any definition
|
||||
that is accessible in the program. The object @scheme[<o2>] may
|
||||
therefore be removed from the evaluation by @defterm{garbage
|
||||
collection}.
|
||||
|
||||
A few special compound datatypes hold @defterm{weak references} to
|
||||
objects. Such weak references are treated specialy by the garbage
|
||||
collector in determining which objects are reachable for the remainder
|
||||
of the computation. If an object is reachable only via a weak
|
||||
reference, then the object can be reclaimed, and the weak reference is
|
||||
replaced by a different value (typically @scheme[#f]).
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Procedure Applications and Local Bindings}
|
||||
|
||||
Given
|
||||
|
||||
@verbatim{ f(x) = x + 10}
|
||||
|
||||
then an algebra student simplifies @tt{f(1)} as follows:
|
||||
|
||||
@verbatim{ f(7) = 7 + 10 = 17}
|
||||
|
||||
The key step in this simplification is take the body of the defined
|
||||
function @tt{f}, and then replace each @tt{x} with the actual value
|
||||
@tt{1}.
|
||||
|
||||
Scheme procedure application works much the same way. A procedure is
|
||||
an object, so evaluating @scheme[(f 7)] starts with a variable lookup:
|
||||
|
||||
@prog-steps[
|
||||
[{(define <p1> (lambda (x) (+ x 10)))}
|
||||
{(define f <p1>)}
|
||||
((code:hilite f) 7)]
|
||||
[{(define <p1> (lambda (x) (+ x 10)))}
|
||||
{(define f <p1>)}
|
||||
(code:hilite (<p1> 7))]
|
||||
]
|
||||
|
||||
Unlike in algebra, however, the value associated with an argument can
|
||||
be changed in the body of a procedure by using @scheme[set!], as in
|
||||
the example @scheme[(lambda (x) (begin (set! x 3) x))]. Since the value
|
||||
associated with @scheme[x] can be changed, an actual value for cannot
|
||||
be substituted for @scheme[x] when the procedure is applied.
|
||||
|
||||
Instead, a new @defterm{location} is created for each variable on each
|
||||
application. The argument value is placed in the location, and each
|
||||
insteace of the variable in the procedure body is replaced with the
|
||||
new location:
|
||||
|
||||
@prog-steps[
|
||||
[{(define <p1> (lambda (x) (+ x 10)))}
|
||||
{(define f <p1>)}
|
||||
(code:hilite (<p1> 7))]
|
||||
[{(define <p1> (lambda (x) (+ x 10)))}
|
||||
{(define f <p1>)
|
||||
(define xloc 7)}
|
||||
(+ (code:hilite xloc) 10)]
|
||||
[{(define <p1> (lambda (x) (+ x 10)))}
|
||||
{(define f <p1>)
|
||||
(define xloc 7)}
|
||||
(code:hilite (+ 7 10))]
|
||||
[{(define <p1> (lambda (x) (+ x 10)))}
|
||||
{(define f <p1>)
|
||||
(define xloc 7)}
|
||||
17]
|
||||
]
|
||||
|
||||
A location is the same as a top-level binding, but when a location is
|
||||
generated, it (conceptually) uses a name that has not been used before
|
||||
and that cannot not be generated again or accessed directly.
|
||||
|
||||
Generating a location in this way means that @scheme[set!] evaluates
|
||||
for local variables in the same way as for top-level bindings, because
|
||||
the variable is always replaced with a location by the time the
|
||||
@scheme[set!] form is evaluated:
|
||||
|
||||
@prog-steps[
|
||||
[{(define <p1> (lambda (x) (begin (set! x 3) x)))}
|
||||
{(define f <p1>)}
|
||||
((code:hilite f) 7)]
|
||||
[{(define <p1> (lambda (x) (begin (set! x 3) x)))}
|
||||
{(define f <p1>)}
|
||||
(code:hilite (<p1> 7))]
|
||||
[{(define <p1> (lambda (x) (begin (set! x 3) x)))}
|
||||
{(define f <p1>)
|
||||
(define xloc 7)}
|
||||
(begin (code:hilite (set! xloc 3)) xloc)]
|
||||
[{(define <p1> (lambda (x) (begin (set! x 3) x)))}
|
||||
{(define f <p1>)
|
||||
(define xloc 3)}
|
||||
(code:hilite (begin #,(void-const) xloc))]
|
||||
[{(define <p1> (lambda (x) (begin (set! x 3) x)))}
|
||||
{(define f <p1>)
|
||||
(define xloc 3)}
|
||||
(code:hilite xloc)]
|
||||
[{(define <p1> (lambda (x) (begin (set! x 3) x)))}
|
||||
{(define f <p1>)
|
||||
(define xloc 3)}
|
||||
3]
|
||||
]
|
||||
|
||||
The substition and location-generation step of procedure application
|
||||
requires that the argument is a value. Therefore, in @scheme[((lambda
|
||||
(x) (+ x 10)) (+ 1 2))], the @scheme[(+ 1 2)] sub-expression must be
|
||||
simplified to the value @scheme[3], and then @scheme[3] can be placed
|
||||
into a location for @scheme[x]. In other words, Scheme is a
|
||||
@defterm{call-by-value} language.
|
||||
|
||||
Evaluation of a local binding, such as @scheme[(let ([x (+ 1 2)])
|
||||
_expr)], is the same as for a procedure call. After @scheme[(+ 1 2)]
|
||||
produces a value, it is stored in a fresh location that replaces every
|
||||
instance of @scheme[x] in @scheme[_expr].
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Identifiers, Variables, and Locations}
|
||||
|
||||
A @defterm{variable} is a placeholder for a value, and an expressions
|
||||
in an initial program refer to variables. A top-level binding is both
|
||||
a variable and a location. Any other variable is always replaced by a
|
||||
location at run-time, so that evaluation of expressions involves only
|
||||
locations. A single non-top-level variable, such as a procedure
|
||||
argument, can correspond to multiple locations at different times.
|
||||
|
||||
The replacement of a variable with a location during evaluation
|
||||
implements Scheme's @defterm{lexical scoping}. For example, when the
|
||||
procedure-argument variable @scheme[x] is replaced by the location
|
||||
@scheme[xloc], then it is replaced throughout the body of the
|
||||
procedure, including with any nested @scheme[lambda] forms. As a
|
||||
result, future references of the variable always access the same
|
||||
location.
|
||||
|
||||
An @defterm{identifier} is source-program entity. Parsing a Scheme
|
||||
program reveals that some identifiers correspond to variables, some
|
||||
refer to syntactic forms, and some are quoted to produce a symbol or a
|
||||
syntax object.
|
||||
|
||||
Throughout the documentation, identifiers are typeset to suggest the
|
||||
way that they are parsed. A black, boldface identifier like
|
||||
@scheme[lambda] indicates as a reference to a syntactic form. A plain
|
||||
blue identifer like @schemeidfont{x} is a variable or a reference to
|
||||
an unspecified top-level definition. A hyperlinked identifier
|
||||
@scheme[cons] is a reference to a specific top-level definition.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Parsing and Compilation}
|
||||
|
||||
The syntax of a Scheme program is defined by
|
||||
|
||||
@itemize{
|
||||
|
||||
@item{a @defterm{read} phase that processes a character stream into a
|
||||
Scheme value, especially one composed of pairs and symbols,
|
||||
and}
|
||||
|
||||
@item{an @defterm{expand} phase that processes the value to finish
|
||||
parsing the code.}
|
||||
|
||||
}
|
||||
|
||||
For details on the read phase, see @secref["mz:reader"]. Source code is
|
||||
normally read in @scheme[read-syntax] mode, otherwise it must be
|
||||
converted to syntax using @scheme[datum->syntax-object]; the expand
|
||||
phase is defined in terms of syntax objects.
|
||||
|
||||
Expansion recursively processes a syntax-wrapped datum; for details,
|
||||
see @secref["mz:expansion"]. Ultimately, expansion leads to the
|
||||
synactic forms described in @secref["mz:syntax"].
|
||||
|
||||
...
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Namespaces}
|
||||
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Threads}
|
||||
|
85
collects/scribblings/reference/prog-steps.ss
Normal file
85
collects/scribblings/reference/prog-steps.ss
Normal file
|
@ -0,0 +1,85 @@
|
|||
|
||||
(module prog-steps mzscheme
|
||||
(require (lib "struct.ss" "scribble")
|
||||
(lib "decode.ss" "scribble")
|
||||
(lib "manual.ss" "scribble")
|
||||
(lib "scheme.ss" "scribble")
|
||||
(lib "kw.ss")
|
||||
(lib "class.ss")
|
||||
(lib "for.ss"))
|
||||
|
||||
(provide prog-steps
|
||||
prog-steps/cont
|
||||
prog-steps/no-obj)
|
||||
|
||||
(define-syntax prog-steps/no-obj
|
||||
(syntax-rules ()
|
||||
[(_ [{def ...} prog] ...)
|
||||
(*prog-steps
|
||||
#f
|
||||
#f
|
||||
(list (schemeblock0 def ...) ...)
|
||||
(list (schemeblock0 prog) ...))]))
|
||||
|
||||
(define-syntax prog-steps
|
||||
(syntax-rules ()
|
||||
[(_ [{obj ...} {def ...} prog] ...)
|
||||
(*prog-steps
|
||||
#f
|
||||
(list (schemeblock0 obj ...) ...)
|
||||
(list (schemeblock0 def ...) ...)
|
||||
(list (schemeblock0 prog) ...))]))
|
||||
|
||||
(define-syntax prog-steps/cont
|
||||
(syntax-rules ()
|
||||
[(_ [{obj ...} {def ...} prog] ...)
|
||||
(*prog-steps
|
||||
#t
|
||||
(list (schemeblock0 obj ...) ...)
|
||||
(list (schemeblock0 def ...) ...)
|
||||
(list (schemeblock0 prog) ...))]))
|
||||
|
||||
(define (to-flow e) (make-flow (list (make-paragraph (list e)))))
|
||||
|
||||
(define (*prog-steps cont? objs defs progs)
|
||||
(make-table
|
||||
'((valignment top top top top top top))
|
||||
(apply
|
||||
append
|
||||
(for/list ([obj (or objs (in-naturals))]
|
||||
[def defs]
|
||||
[prog progs]
|
||||
[i (in-naturals)])
|
||||
(let ([l
|
||||
(list
|
||||
(list (to-flow " ")
|
||||
(to-flow (if (and (or (positive? i)
|
||||
cont?)
|
||||
(not objs))
|
||||
'rarr
|
||||
" "))
|
||||
(to-flow " ")
|
||||
(to-flow "defined:")
|
||||
(to-flow " ")
|
||||
(make-flow (list def)))
|
||||
(list (to-flow " ")
|
||||
(to-flow " ")
|
||||
(to-flow " ")
|
||||
(to-flow "evaluate:")
|
||||
(to-flow " ")
|
||||
(make-flow (list prog))))])
|
||||
(if objs
|
||||
(cons (list
|
||||
(to-flow " ")
|
||||
(to-flow (if (or (positive? i)
|
||||
cont?)
|
||||
'rarr
|
||||
" "))
|
||||
(to-flow " ")
|
||||
(to-flow "objects:")
|
||||
(to-flow " ")
|
||||
(make-flow (list obj)))
|
||||
l)
|
||||
l)))))))
|
||||
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
@define[(graph-defn) @elem{@litchar{#}@graph-tag[]@litchar{=}}]
|
||||
@define[(graph-ref) @elem{@litchar{#}@graph-tag[]@litchar{#}}]
|
||||
|
||||
@title[#:tag "mz:reader"]{Reading Data}
|
||||
@title[#:tag "mz:reader"]{Reading}
|
||||
|
||||
Scheme's reader is a recursive-descent parser that can be configured
|
||||
through a @seclink["readtable"]{readtable} and various other
|
||||
|
|
|
@ -3,10 +3,18 @@
|
|||
|
||||
@title{PLT Scheme Reference Manual}
|
||||
|
||||
This manual defines the core PLT Scheme language and describes its
|
||||
most prominent libraries. The companion manual
|
||||
@italic{@link["../guide/index.html"]{A Guide to PLT Scheme}} provides
|
||||
a friendlier (though less precise and complete) overview of the
|
||||
language.
|
||||
|
||||
@table-of-contents[]
|
||||
|
||||
@include-section["data.scrbl"]
|
||||
@include-section["syntax.scrbl"]
|
||||
@include-section["model.scrbl"]
|
||||
@include-section["read.scrbl"]
|
||||
@include-section["macros.scrbl"]
|
||||
@include-section["syntax.scrbl"]
|
||||
@include-section["data.scrbl"]
|
||||
|
||||
@index-section["mzscheme-index"]
|
||||
|
|
|
@ -1,48 +1,37 @@
|
|||
#reader(lib "docreader.ss" "scribble")
|
||||
@require["mz.ss"]
|
||||
|
||||
@title{Syntax}
|
||||
|
||||
The syntax of a Scheme program is defined by
|
||||
|
||||
@itemize{
|
||||
|
||||
@item{a @defterm{read} phase that processes a character stream into a
|
||||
Scheme value, especially one composed of pairs and symbols,
|
||||
and}
|
||||
|
||||
@item{an @defterm{expand} phase that processes the value to finish
|
||||
parsing the code.}
|
||||
|
||||
}
|
||||
|
||||
For details on the read phase, see @secref["mz:reader"]. Source code is
|
||||
normally read in @scheme[read-syntax] mode, otherwise it must be
|
||||
converted to syntax using @scheme[datum->syntax-object]; the expand
|
||||
phase is defined in terms of syntax objects.
|
||||
|
||||
Expansion recursively processes a syntax-wrapped datum; for details,
|
||||
see @secref["mz:expansion"]. Ultimately, expansion leads to the
|
||||
synactic forms described in this section.
|
||||
@title[#:tag "mz:syntax"]{Core Syntactic Forms}
|
||||
|
||||
A syntactic form is described by a BNF-like notation that describes a
|
||||
combination of (syntax-wrapped) pairs, symbols, and other data (not a
|
||||
sequence of characters). In this notation, @scheme[...] indicates zero
|
||||
or more repetitions of the preceding datum, @scheme[...+] indicates
|
||||
one or more repetitions, and @scheme[?] means zero or one
|
||||
instance. Italic sequences of characters play the role of
|
||||
non-terminals. In particular:
|
||||
sequence of characters):
|
||||
|
||||
@itemize{
|
||||
|
||||
@item{A sequence that ends in @scheme[_id] refers to a syntax-wrapped
|
||||
symbol.}
|
||||
@item{@scheme[...] indicates zero or more
|
||||
repetitions of the preceding datum.}
|
||||
|
||||
@item{@scheme[...+] indicates one or
|
||||
more repetitions of the preceding datum.}
|
||||
|
||||
@item{@scheme[?] means zero instances or one instance
|
||||
of the preceding datum.}
|
||||
|
||||
@item{Italic sequences of characters play the role of non-terminals. In
|
||||
particular:
|
||||
|
||||
@itemize{
|
||||
|
||||
@item{A sequence that ends in @scheme[_id] refers to a
|
||||
syntax-wrapped symbol.}
|
||||
|
||||
@item{A sequence that ends in @scheme[_keyword] refers to a
|
||||
syntax-wrapped keyword.}
|
||||
|
||||
@item{A sequence that end with @scheme[_expr] refers to a sub-form
|
||||
that is expanded as an expression.}
|
||||
}}
|
||||
}
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
|
|
129
collects/tests/mzscheme/for.ss
Normal file
129
collects/tests/mzscheme/for.ss
Normal file
|
@ -0,0 +1,129 @@
|
|||
|
||||
(load-relative "loadtest.ss")
|
||||
|
||||
(require (lib "for.ss"))
|
||||
|
||||
(Section 'generator)
|
||||
|
||||
(define-syntax (test-multi-generator stx)
|
||||
(syntax-case stx ()
|
||||
[(_ [(v ...) ...] gen)
|
||||
(with-syntax ([(id ...) (generate-temporaries #'((v ...) ...))]
|
||||
[(id2 ...) (generate-temporaries #'((v ...) ...))]
|
||||
[((v2 ...) ...)
|
||||
(apply map list (map syntax->list (syntax->list #'((v ...) ...))))])
|
||||
#'(begin
|
||||
(test '((v2 ...) ...) 'gen (for/list-values ([(id ...) gen])
|
||||
(list id ...)))
|
||||
(test-values '((v ...) ...) (lambda ()
|
||||
(for/lists-values (id2 ...) ([(id ...) gen])
|
||||
(values id ...))))
|
||||
(test #t 'gen (for/and-values ([(id ...) gen])
|
||||
(and (member (list id ...) '((v2 ...) ...)) #t)))
|
||||
(test (list (for/last-values ([(id ...) gen])
|
||||
(list id ...)))
|
||||
'gen (for/and-values ([(id ...) gen])
|
||||
(member (list id ...) '((v2 ...) ...))))
|
||||
(test (for/first-values ([(id ...) gen])
|
||||
(list id ...))
|
||||
'gen (for/or-values ([(id ...) gen])
|
||||
(car (member (list id ...) '((v2 ...) ...)))))
|
||||
(void)))]))
|
||||
|
||||
(define-syntax test-generator
|
||||
(syntax-rules ()
|
||||
[(_ [seq] gen) ; we assume that seq has at least 2 elements, and all are unique
|
||||
(begin
|
||||
;; Some tests specific to single-values:
|
||||
(test 'seq 'gen (for/list ([i gen]) i))
|
||||
(test 'seq 'gen (for/list ([i gen][b gen]) i))
|
||||
(test 'seq 'gen (for/list ([i gen][b gen]) b))
|
||||
(test 'seq 'gen (for*/list ([i gen][b '(#t)]) i))
|
||||
(test (map (lambda (x) #t) 'seq) 'gen (for*/list ([i gen][b '(#t)]) b))
|
||||
(test (append 'seq 'seq) 'gen (for*/list ([b '(#f #t)][i gen]) i))
|
||||
(test (append 'seq 'seq) 'gen (for/list ([b '(#f #t)] #:when #t [i gen]) i))
|
||||
(test 'seq 'gen (let ([g gen]) (for/list ([i g]) i)))
|
||||
(test 'seq 'gen (let ([r null])
|
||||
(for ([i gen]) (set! r (cons i r)))
|
||||
(reverse r)))
|
||||
(test 'seq 'gen (reverse (for/fold ([a null]) ([i gen])
|
||||
(cons i a))))
|
||||
(test 'seq 'gen (let-values ([(more? next) (sequence-generator gen)])
|
||||
(let loop ()
|
||||
(if (more?)
|
||||
(cons (next) (loop))
|
||||
null))))
|
||||
(test-values '(seq seq) (lambda ()
|
||||
(for/lists (r1 r2) ([id gen])
|
||||
(values id id))))
|
||||
(test (list (for/last ([i gen]) i)) 'gen (for/and ([i gen]) (member i 'seq)))
|
||||
(test 'seq 'gen (for/or ([i gen]) (member i 'seq)))
|
||||
(test (for/first ([i gen]) i) 'gen (for/or ([i gen]) (and (member i 'seq) i)))
|
||||
(test #t 'gen (for/and-values ([(i k) (in-parallel gen 'seq)])
|
||||
(equal? i k)))
|
||||
(test #f 'gen (for/and ([i gen])
|
||||
(member i (cdr (reverse 'seq)))))
|
||||
(test #f 'gen (for/or ([i gen]) (equal? i 'something-else)))
|
||||
(let ([count 0])
|
||||
(test #t 'or (for/or ([i gen]) (set! count (add1 count)) #t))
|
||||
(test 1 'count count)
|
||||
(test #f 'or (for/or ([i gen]) (set! count (add1 count)) #f))
|
||||
(test (+ 1 (length 'seq)) 'count count)
|
||||
(set! count 0)
|
||||
(let ([second (for/last-values ([(i pos) (in-parallel gen (in-naturals))] #:when (< pos 2))
|
||||
(set! count (add1 count))
|
||||
i)])
|
||||
(test second list-ref 'seq 1)
|
||||
(test 2 values count)
|
||||
(for ([i gen] #:when (equal? i second)) (set! count (add1 count)))
|
||||
(for* ([i gen] #:when (equal? i second)) (set! count (add1 count)))
|
||||
(test 4 values count)
|
||||
(for ([i (stop-before gen (lambda (x) (equal? x second)))]) (set! count (add1 count)))
|
||||
(test 5 values count)
|
||||
(let ([g (stop-before gen (lambda (x) (equal? x second)))])
|
||||
(for ([i g]) (set! count (add1 count))))
|
||||
(test 6 values count)
|
||||
(for ([i (stop-after gen (lambda (x) (equal? x second)))]) (set! count (add1 count)))
|
||||
(test 8 values count)
|
||||
(let ([g (stop-after gen (lambda (x) (equal? x second)))])
|
||||
(for ([i g]) (set! count (add1 count))))
|
||||
(test 10 values count))
|
||||
(set! count 0)
|
||||
(test #t 'and (for/and-values ([(e idx) (in-indexed gen)]) (set! count (add1 count)) (equal? idx (sub1 count))))
|
||||
(test #t 'and (let ([g (in-indexed gen)])
|
||||
(set! count 0)
|
||||
(for/and-values ([(e idx) g]) (set! count (add1 count)) (equal? idx (sub1 count)))))
|
||||
(void))
|
||||
;; Run multi-value tests:
|
||||
(test-multi-generator [seq] gen))]
|
||||
[(_ seqs gen)
|
||||
(test-multi-generator seqs gen)]))
|
||||
|
||||
(test-generator [(0 1 2)] (in-range 3))
|
||||
(test-generator [(3 4 5)] (in-range 3 6))
|
||||
(test-generator [(7 6 5)] (in-range 7 4 -1))
|
||||
|
||||
(test-generator [(a b c)] '(a b c))
|
||||
(test-generator [(a b c)] (in-list '(a b c)))
|
||||
(test-generator [(a b c)] #(a b c))
|
||||
(test-generator [(a b c)] (in-vector #(a b c)))
|
||||
(test-generator [(#\a #\b #\c)] "abc")
|
||||
(test-generator [(#\a #\b #\c)] (in-string "abc"))
|
||||
(test-generator [(65 66 67)] #"ABC")
|
||||
(test-generator [(65 66 67)] (in-bytes #"ABC"))
|
||||
(test-generator [(#\a #\b #\c)] (in-input-port-chars (open-input-string "abc")))
|
||||
(test-generator [(65 66 67)] (open-input-bytes #"ABC"))
|
||||
(test-generator [(65 66 67)] (in-input-port-bytes (open-input-bytes #"ABC")))
|
||||
|
||||
(test-generator [(0 1 2) (a b c)] (in-parallel (in-range 3) (in-list '(a b c))))
|
||||
(test-generator [(0 1 2) (a b c)] (in-parallel (in-range 10) (in-list '(a b c))))
|
||||
(test-generator [(0 1 2) (a b c)] (in-parallel (in-range 3) (in-list '(a b c d))))
|
||||
(test-generator [(0 1 2) (a b c)] (in-parallel (in-range 3) '(a b c)))
|
||||
|
||||
(test-generator [(a b c)] (stop-after (in-list '(a b c d e)) (lambda (x) (equal? x 'c))))
|
||||
(test-generator [(a b c)] (stop-before (in-list '(a b c d e)) (lambda (x) (equal? x 'd))))
|
||||
(test-generator [(3 4 5)] (stop-before (in-naturals 3) (lambda (x) (= x 6))))
|
||||
|
||||
(test-generator [(a b c) (0 1 2)] (in-indexed '(a b c)))
|
||||
|
||||
(report-errs)
|
Loading…
Reference in New Issue
Block a user