Lots of documentation formatting.
Started as fixing misindented definitions, then more indentations, then a bunch of similar things (square brackets, huge spaces at end-of-lines, etc).
This commit is contained in:
parent
d3d9514b1c
commit
d61eb53686
|
@ -16,8 +16,8 @@
|
|||
|
||||
@(define-syntax-rule (def-ext id)
|
||||
(begin
|
||||
(require (for-label net/sendurl))
|
||||
(define id (racket send-url))))
|
||||
(require (for-label net/sendurl))
|
||||
(define id (racket send-url))))
|
||||
@(def-ext net-send-url)
|
||||
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ Zum Beispiel:
|
|||
(define pos (make-vec3 5 5 3))
|
||||
(define lookat (make-vec3 0 0 0))
|
||||
(define camera
|
||||
(create-camera-matrix pos lookat 70.0 screenWidth screenHeight))
|
||||
(create-camera-matrix pos lookat 70.0 screenWidth screenHeight))
|
||||
(code:comment @#,t{render image})
|
||||
(render-scene screenWidth screenHeight box camera)
|
||||
]
|
||||
|
|
|
@ -19,16 +19,16 @@
|
|||
|
||||
@(define-syntax-rule (defprocthing* mod id ...)
|
||||
(begin
|
||||
(deflazy mod defprocthing id)
|
||||
...))
|
||||
(deflazy mod defprocthing id)
|
||||
...))
|
||||
|
||||
@(define-syntax-rule (defprocthing id . rest)
|
||||
(defthing id procedure? . rest))
|
||||
|
||||
@(define-syntax-rule (defidform* mod id ...)
|
||||
(begin
|
||||
(deflazy mod defidform id)
|
||||
...))
|
||||
(deflazy mod defidform id)
|
||||
...))
|
||||
|
||||
@; ----------------------------------------
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
@(define-syntax-rule (intro id)
|
||||
(begin
|
||||
(require (for-label racket/cmdline))
|
||||
(define id (racket command-line))))
|
||||
(require (for-label racket/cmdline))
|
||||
(define id (racket command-line))))
|
||||
@(intro racket-command-line)
|
||||
|
||||
@mzlib[#:mode title cmdline]
|
||||
|
|
|
@ -13,12 +13,12 @@
|
|||
@interaction-eval[#:eval etc-eval (require mzlib/etc)]
|
||||
|
||||
@(begin
|
||||
(define-syntax-rule (bind id else-id)
|
||||
(begin
|
||||
(require (for-label scheme/base))
|
||||
(define id (racket lambda))
|
||||
(define else-id (racket else))))
|
||||
(bind base-lambda base-else))
|
||||
(define-syntax-rule (bind id else-id)
|
||||
(begin
|
||||
(require (for-label scheme/base))
|
||||
(define id (racket lambda))
|
||||
(define else-id (racket else))))
|
||||
(bind base-lambda base-else))
|
||||
|
||||
@mzlib[#:mode title etc]
|
||||
|
||||
|
@ -77,11 +77,11 @@ syntax transformers that share helper functions, though
|
|||
(define-syntax-set (let-current-continuation
|
||||
let-current-escape-continuation)
|
||||
(define (mk call-id)
|
||||
(lambda (stx)
|
||||
(syntax-case stx ()
|
||||
[(_ id body1 body ...)
|
||||
(with-syntax ([call call-id])
|
||||
(syntax (call (lambda (id) body1 body ...))))])))
|
||||
(lambda (stx)
|
||||
(syntax-case stx ()
|
||||
[(_ id body1 body ...)
|
||||
(with-syntax ([call call-id])
|
||||
(syntax (call (lambda (id) body1 body ...))))])))
|
||||
(define let-current-continuation/proc
|
||||
(mk (quote-syntax call/cc)))
|
||||
(define let-current-escape-continuation/proc
|
||||
|
@ -156,12 +156,12 @@ corresponding expression are bound to the multiple variables.
|
|||
@examples[
|
||||
#:eval etc-eval
|
||||
(let+ ([val (values x y) (values 1 2)])
|
||||
(list x y))
|
||||
(list x y))
|
||||
|
||||
(let ([x 1])
|
||||
(let+ ([val x 3]
|
||||
[val y x])
|
||||
y))
|
||||
(let+ ([val x 3]
|
||||
[val y x])
|
||||
y))
|
||||
]}
|
||||
|
||||
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
@interaction-eval[#:eval kw-eval (require mzlib/kw)]
|
||||
|
||||
@(begin
|
||||
(define-syntax-rule (bind id)
|
||||
(begin
|
||||
(require (for-label scheme/base))
|
||||
(define id (racket lambda))))
|
||||
(bind base-lambda))
|
||||
(define-syntax-rule (bind id)
|
||||
(begin
|
||||
(require (for-label scheme/base))
|
||||
(define id (racket lambda))))
|
||||
(bind base-lambda))
|
||||
|
||||
@mzlib[#:mode title kw]
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
@(begin
|
||||
(define-syntax-rule (bind id)
|
||||
(begin
|
||||
(require racket/match)
|
||||
(define id (racket match))))
|
||||
(require racket/match)
|
||||
(define id (racket match))))
|
||||
(bind racket-match))
|
||||
|
||||
@mzlib[#:mode title match]
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
(only-in racket/sandbox make-module-evaluator)))
|
||||
|
||||
@(begin
|
||||
(define-syntax-rule (bind id)
|
||||
(begin
|
||||
(require (for-label racket/sandbox))
|
||||
(define id (racket make-evaluator))))
|
||||
(bind racket-make-evaluator))
|
||||
(define-syntax-rule (bind id)
|
||||
(begin
|
||||
(require (for-label racket/sandbox))
|
||||
(define id (racket make-evaluator))))
|
||||
(bind racket-make-evaluator))
|
||||
|
||||
@mzlib[#:mode title sandbox]
|
||||
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
(for-label mzlib/sendevent))
|
||||
|
||||
@(begin
|
||||
(define-syntax-rule (bind id)
|
||||
(begin
|
||||
(require (for-label scheme/gui/base))
|
||||
(define id (racket send-event))))
|
||||
(bind mred-send-event))
|
||||
(define-syntax-rule (bind id)
|
||||
(begin
|
||||
(require (for-label scheme/gui/base))
|
||||
(define id (racket send-event))))
|
||||
(bind mred-send-event))
|
||||
|
||||
@mzlib[#:mode title sendevent]
|
||||
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
(for-label mzlib/serialize))
|
||||
|
||||
@(begin
|
||||
(define-syntax-rule (bind id id2)
|
||||
(begin
|
||||
(require (for-label racket/serialize))
|
||||
(define id (racket define-serializable-struct))
|
||||
(define id2 (racket define-serializable-struct/versions))))
|
||||
(bind racket-define-serializable-struct racket-define-serializable-struct/versions))
|
||||
(define-syntax-rule (bind id id2)
|
||||
(begin
|
||||
(require (for-label racket/serialize))
|
||||
(define id (racket define-serializable-struct))
|
||||
(define id2 (racket define-serializable-struct/versions))))
|
||||
(bind racket-define-serializable-struct
|
||||
racket-define-serializable-struct/versions))
|
||||
|
||||
@mzlib[#:mode title serialize]
|
||||
|
||||
|
|
|
@ -52,10 +52,10 @@ property.
|
|||
@examples[
|
||||
#:eval struct-eval
|
||||
(define-struct/properties point (x y)
|
||||
([prop:custom-write (lambda (p port write?)
|
||||
(fprintf port "(~a, ~a)"
|
||||
(point-x p)
|
||||
(point-y p)))]))
|
||||
([prop:custom-write (lambda (p port write?)
|
||||
(fprintf port "(~a, ~a)"
|
||||
(point-x p)
|
||||
(point-y p)))]))
|
||||
(display (make-point 1 2))
|
||||
]}
|
||||
|
||||
|
|
|
@ -10,13 +10,13 @@ library provides working versions of @racket[transcript-on] and
|
|||
@racket[transcript-off].
|
||||
|
||||
@(define-syntax-rule (go)
|
||||
(begin
|
||||
(require (for-label mzlib/transcr))
|
||||
(begin
|
||||
(require (for-label mzlib/transcr))
|
||||
|
||||
@deftogether[(
|
||||
@defproc[(transcript-on [filename any/c]) any]
|
||||
@defproc[(transcript-off) any]
|
||||
)]{
|
||||
@deftogether[(
|
||||
@defproc[(transcript-on [filename any/c]) any]
|
||||
@defproc[(transcript-off) any]
|
||||
)]{
|
||||
|
||||
Starts/stops recording a transcript at @racket[filename].}))
|
||||
@(go)
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
(for-label mzlib/unit))
|
||||
|
||||
@(begin
|
||||
(define-syntax-rule (bind id)
|
||||
(begin
|
||||
(require (for-label racket/unit))
|
||||
(define id (racket struct))))
|
||||
(bind racket-struct)
|
||||
(define-syntax-rule (bindc id)
|
||||
(begin
|
||||
(require (for-label racket/unit))
|
||||
(define id (racket struct/ctc))))
|
||||
(bindc racket-struct/ctc))
|
||||
(define-syntax-rule (bind id)
|
||||
(begin
|
||||
(require (for-label racket/unit))
|
||||
(define id (racket struct))))
|
||||
(bind racket-struct)
|
||||
(define-syntax-rule (bindc id)
|
||||
(begin
|
||||
(require (for-label racket/unit))
|
||||
(define id (racket struct/ctc))))
|
||||
(bindc racket-struct/ctc))
|
||||
|
||||
@mzlib[#:mode title unit]
|
||||
|
||||
|
|
|
@ -22,22 +22,22 @@
|
|||
base-free-identifier=? base-free-template-identifier=?
|
||||
base-free-transformer-identifier=? base-free-label-identifier=?)
|
||||
(begin
|
||||
(require (for-label scheme/base))
|
||||
(define base-define (racket define))
|
||||
(define base-define-syntax (racket define-syntax))
|
||||
(define base-define-for-syntax (racket define-for-syntax))
|
||||
(define base-define-struct (racket define-struct))
|
||||
(define base-if (racket if))
|
||||
(define base-cond (racket cond))
|
||||
(define base-case (racket case))
|
||||
(define base-top-interaction (racket #%top-interaction))
|
||||
(define base-open-input-file (racket open-input-file))
|
||||
(define base-apply (racket apply))
|
||||
(define base-prop:procedure (racket prop:procedure))
|
||||
(define base-free-identifier=? (racket free-identifier=?))
|
||||
(define base-free-template-identifier=? (racket free-template-identifier=?))
|
||||
(define base-free-transformer-identifier=? (racket free-transformer-identifier=?))
|
||||
(define base-free-label-identifier=? (racket free-label-identifier=?))))
|
||||
(require (for-label scheme/base))
|
||||
(define base-define (racket define))
|
||||
(define base-define-syntax (racket define-syntax))
|
||||
(define base-define-for-syntax (racket define-for-syntax))
|
||||
(define base-define-struct (racket define-struct))
|
||||
(define base-if (racket if))
|
||||
(define base-cond (racket cond))
|
||||
(define base-case (racket case))
|
||||
(define base-top-interaction (racket #%top-interaction))
|
||||
(define base-open-input-file (racket open-input-file))
|
||||
(define base-apply (racket apply))
|
||||
(define base-prop:procedure (racket prop:procedure))
|
||||
(define base-free-identifier=? (racket free-identifier=?))
|
||||
(define base-free-template-identifier=? (racket free-template-identifier=?))
|
||||
(define base-free-transformer-identifier=? (racket free-transformer-identifier=?))
|
||||
(define base-free-label-identifier=? (racket free-label-identifier=?))))
|
||||
@(def-base base-define base-define-syntax base-define-for-syntax base-define-struct
|
||||
base-if base-cond base-case base-top-interaction
|
||||
base-open-input-file base-apply base-prop:procedure
|
||||
|
|
|
@ -110,11 +110,11 @@ Raised for errors when handling cookies.}
|
|||
@subsection{Creating a cookie}
|
||||
|
||||
@racketblock[
|
||||
(let ((c (cookie:add-max-age
|
||||
(let ([c (cookie:add-max-age
|
||||
(cookie:add-path
|
||||
(set-cookie "foo" "bar")
|
||||
"/servlets")
|
||||
3600)))
|
||||
3600)])
|
||||
(print-cookie c))
|
||||
]
|
||||
|
||||
|
|
|
@ -343,7 +343,7 @@ characters, @racket[char-lower-case?] characters, etc.}
|
|||
@(define-syntax-rule (lex-sre-doc)
|
||||
(...
|
||||
(begin
|
||||
(require (for-label parser-tools/lex-sre))
|
||||
(require (for-label parser-tools/lex-sre))
|
||||
|
||||
@defform[(* re ...)]{
|
||||
|
||||
|
@ -417,7 +417,7 @@ characters.}
|
|||
@(define-syntax-rule (lex-v200-doc)
|
||||
(...
|
||||
(begin
|
||||
(require (for-label parser-tools/lex-plt-v200))
|
||||
(require (for-label parser-tools/lex-plt-v200))
|
||||
|
||||
@t{The @racketmodname[parser-tools/lex-plt-v200] module re-exports
|
||||
@racket[*], @racket[+], @racket[?], and @racket[&] from
|
||||
|
|
|
@ -199,19 +199,19 @@ the bounds of the image, returns a transparent color.}
|
|||
[f (-> natural-number/c natural-number/c color?)])
|
||||
image?]{
|
||||
|
||||
Builds an image of the specified size and shape by calling the specified function
|
||||
on the coordinates of each pixel. For example,
|
||||
Builds an image of the specified size and shape by calling the specified
|
||||
function on the coordinates of each pixel. For example,
|
||||
@codeblock|{
|
||||
; fuzz : image -> image
|
||||
(define (fuzz pic)
|
||||
(local [; near-pixel : num(x) num(y) -> color
|
||||
(define (near-pixel x y)
|
||||
(get-pixel-color (+ x -3 (random 7))
|
||||
(+ y -3 (random 7))
|
||||
pic))]
|
||||
(build-image (image-width pic)
|
||||
(image-height pic)
|
||||
near-pixel)))
|
||||
(local [; near-pixel : num(x) num(y) -> color
|
||||
(define (near-pixel x y)
|
||||
(get-pixel-color (+ x -3 (random 7))
|
||||
(+ y -3 (random 7))
|
||||
pic))]
|
||||
(build-image (image-width pic)
|
||||
(image-height pic)
|
||||
near-pixel)))
|
||||
}|
|
||||
produces a fuzzy version of the given picture by replacing each pixel with a
|
||||
randomly chosen pixel near it.}
|
||||
|
@ -268,7 +268,7 @@ size and shape. For example,
|
|||
@codeblock|{
|
||||
; lose-red : num(x) num(y) color -> color
|
||||
(define (lose-red x y old-color)
|
||||
(make-color 0 (color-green old-color) (color-blue old-color)))
|
||||
(make-color 0 (color-green old-color) (color-blue old-color)))
|
||||
|
||||
(map-image lose-red my-picture)}|
|
||||
produces a copy of @racket[my-picture] with all the red leached out,
|
||||
|
@ -286,9 +286,9 @@ Another example:
|
|||
@codeblock|{
|
||||
; apply-gradient : num(x) num(y) color -> color
|
||||
(define (apply-gradient x y old-color)
|
||||
(make-color (min (* 3 x) 255)
|
||||
0
|
||||
(min (* 3 y) 255)))
|
||||
(make-color (min (* 3 x) 255)
|
||||
0
|
||||
(min (* 3 y) 255)))
|
||||
|
||||
(map-image apply-gradient my-picture)}|
|
||||
produces a picture the size of @racket[my-picture]'s bounding rectangle,
|
||||
|
@ -402,12 +402,12 @@ For example,
|
|||
@codeblock|{
|
||||
; bad-gradient : num(x) num(y) -> color
|
||||
(define (bad-gradient x y)
|
||||
(make-color (* 2.5 x) (* 1.6 y) 0))
|
||||
(make-color (* 2.5 x) (* 1.6 y) 0))
|
||||
(build-image 50 30 bad-gradient)
|
||||
|
||||
; good-gradient : num(x) num(y) -> color
|
||||
(define (good-gradient x y)
|
||||
(make-color (real->int (* 2.5 x)) (real->int (* 1.6 y)) 0))
|
||||
(make-color (real->int (* 2.5 x)) (real->int (* 1.6 y)) 0))
|
||||
(build-image 50 30 good-gradient)
|
||||
}|
|
||||
The version using @racket[bad-gradient] crashes because color components must be exact integers.
|
||||
|
@ -462,15 +462,15 @@ its output into a string, which is returned. Especially useful for testing:
|
|||
@codeblock|{
|
||||
; ask : string -> prints output, waits for text input, returns it
|
||||
(define (ask question)
|
||||
(begin (display question)
|
||||
(read)))
|
||||
(begin (display question)
|
||||
(read)))
|
||||
; greet : nothing -> prints output, waits for text input, prints output
|
||||
(define (greet)
|
||||
(local [(define name (ask "What is your name?"))]
|
||||
(printf "Hello, ~a!" name)))
|
||||
(local [(define name (ask "What is your name?"))]
|
||||
(printf "Hello, ~a!" name)))
|
||||
(check-expect
|
||||
(with-io-strings "Steve" greet)
|
||||
"What is your name?Hello, Steve!")}|
|
||||
(with-io-strings "Steve" greet)
|
||||
"What is your name?Hello, Steve!")}|
|
||||
}
|
||||
|
||||
@; @include-section{worlds.scrbl}
|
||||
|
|
|
@ -229,7 +229,6 @@ The @racket[pkg] argument must end with @racket[".plt"].
|
|||
}
|
||||
|
||||
|
||||
|
||||
@defproc[(get-package-spec [owner string?]
|
||||
[pkg (and/c string? #rx"[.]plt$")]
|
||||
[maj (or/c #f natural-number/c) #f]
|
||||
|
@ -284,7 +283,8 @@ See also @racket[build-scribble-docs?] and @racket[force-package-building?]
|
|||
}
|
||||
|
||||
@defparam[force-package-building? b boolean?]{
|
||||
Determines if @racket[make-planet-archive] is more strict and thus aborts more often.
|
||||
Determines if @racket[make-planet-archive] is more strict and thus
|
||||
aborts more often.
|
||||
}
|
||||
|
||||
@defproc[(download-package [pkg-spec pkg-spec?])
|
||||
|
@ -418,7 +418,8 @@ produces a list corresponding to its name and version, exactly like
|
|||
}
|
||||
|
||||
@defproc[(pkg? [v any/c]) boolean?]{
|
||||
Determines if its argument is a pkg, the representation of an installed package.
|
||||
Determines if its argument is a pkg, the representation of an
|
||||
installed package.
|
||||
}
|
||||
|
||||
@section[#:tag "version.rkt"]{Package Version}
|
||||
|
|
|
@ -181,15 +181,15 @@ function, we could do the following:
|
|||
#:segments [segments 20]
|
||||
#:color [color 'red]
|
||||
#:width [width 1])
|
||||
(let* ((dash-size (/ (- x-max x-min) segments))
|
||||
(x-lists (build-list
|
||||
(let* ([dash-size (/ (- x-max x-min) segments)]
|
||||
[x-lists (build-list
|
||||
(/ segments 2)
|
||||
(lambda (index)
|
||||
(x-values
|
||||
(/ samples segments)
|
||||
(+ x-min (* 2 index dash-size))
|
||||
(+ x-min (* (add1 (* 2 index))
|
||||
dash-size)))))))
|
||||
dash-size)))))])
|
||||
(lambda (2dview)
|
||||
(send 2dview set-line-color color)
|
||||
(send 2dview set-line-width width)
|
||||
|
|
|
@ -399,7 +399,7 @@ Dispatching-related bindings:
|
|||
|
||||
@racketblock[
|
||||
(define (ttref)
|
||||
(let ((url (get-arg)) (text (get-arg)))
|
||||
(let ([url (get-arg)] [text (get-arg)])
|
||||
(list "<a href=\"" url "\">@tt{" text "}</a>")))
|
||||
]
|
||||
|
||||
|
|
|
@ -247,8 +247,8 @@ Here's the implementation of @racket[fold-test-results] in terms of
|
|||
kid-seed)
|
||||
(lambda (case name action seed)
|
||||
(case-fn
|
||||
(run-test-case name action)
|
||||
seed))
|
||||
(run-test-case name action)
|
||||
seed))
|
||||
seed
|
||||
test))
|
||||
]
|
||||
|
|
|
@ -76,7 +76,7 @@ cases. Here's a simple test case written using the
|
|||
|
||||
@racketblock[
|
||||
(test-begin
|
||||
(let ((lst (list 2 4 6 9)))
|
||||
(let ([lst (list 2 4 6 9)])
|
||||
(check = (length lst) 4)
|
||||
(for-each
|
||||
(lambda (elt)
|
||||
|
@ -111,7 +111,7 @@ we're testing. We can give a test case a name with the
|
|||
@racketblock[
|
||||
(test-case
|
||||
"List has length 4 and all elements even"
|
||||
(let ((lst (list 2 4 6 9)))
|
||||
(let ([lst (list 2 4 6 9)])
|
||||
(check = (length lst) 4)
|
||||
(for-each
|
||||
(lambda (elt)
|
||||
|
@ -133,7 +133,7 @@ group them into a test suite:
|
|||
|
||||
(test-case
|
||||
"List has length 4 and all elements even"
|
||||
(let ((lst (list 2 4 6 9)))
|
||||
(let ([lst (list 2 4 6 9)])
|
||||
(check = (length lst) 4)
|
||||
(for-each
|
||||
(lambda (elt)
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
(apply item @index[(map (lambda (x) (format "~a keybinding" x)) keys) key-str] " : " desc)))
|
||||
|
||||
@(define-syntax-rule (def-mod-beg id)
|
||||
(begin
|
||||
(require (for-label racket/base))
|
||||
(define id @racket[#%module-begin])))
|
||||
(begin
|
||||
(require (for-label racket/base))
|
||||
(define id @racket[#%module-begin])))
|
||||
@(def-mod-beg mz-mod-begin)
|
||||
|
||||
@title{Keyboard Shortcuts}
|
||||
|
|
|
@ -36,15 +36,15 @@
|
|||
@racketblock[
|
||||
(class ...
|
||||
...
|
||||
(define status-panel #f)
|
||||
(define/override (make-root-area-container cls parent)
|
||||
(set! status-panel
|
||||
(super make-root-area-container vertical-panel% parent))
|
||||
(let ([root (make-object cls status-panel)])
|
||||
(define status-panel #f)
|
||||
(define/override (make-root-area-container cls parent)
|
||||
(set! status-panel
|
||||
(super make-root-area-container vertical-panel% parent))
|
||||
(let ([root (make-object cls status-panel)])
|
||||
|
||||
(code:comment "... add other children to status-panel ...")
|
||||
(code:comment "... add other children to status-panel ...")
|
||||
|
||||
root))
|
||||
root))
|
||||
...)]
|
||||
|
||||
In this example, status-panel will contain a root panel for the other
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
(except-in wxme/cache-image reader)))
|
||||
|
||||
@(define-syntax-rule (in mod . content)
|
||||
(begin
|
||||
(define-syntax-rule (intro)
|
||||
(begin (require (for-label mod))
|
||||
. content))
|
||||
(intro)))
|
||||
(begin
|
||||
(define-syntax-rule (intro)
|
||||
(begin (require (for-label mod))
|
||||
. content))
|
||||
(intro)))
|
||||
|
||||
@title{WXME Decoding}
|
||||
|
||||
|
|
|
@ -94,8 +94,8 @@ apply a function like @racket[+] to all of the items in the list:
|
|||
|
||||
@def+int[
|
||||
(define (avg lst) (code:comment @#,elem{doesn't always work...})
|
||||
(/ (+ (list-ref lst 0) (list-ref lst 1) (list-ref lst 2))
|
||||
(length lst)))
|
||||
(/ (+ (list-ref lst 0) (list-ref lst 1) (list-ref lst 2))
|
||||
(length lst)))
|
||||
(avg '(1 2 3))
|
||||
(avg '(1 2))
|
||||
]
|
||||
|
|
|
@ -28,9 +28,9 @@ tail position with respect to the @racket[begin] form.
|
|||
(if (zero? height)
|
||||
(void)
|
||||
(begin
|
||||
(display (make-string height #\*))
|
||||
(newline)
|
||||
(print-triangle (sub1 height)))))
|
||||
(display (make-string height #\*))
|
||||
(newline)
|
||||
(print-triangle (sub1 height)))))
|
||||
(print-triangle 4)
|
||||
]
|
||||
|
||||
|
@ -55,10 +55,10 @@ positions, instead of forming an expression, the content of
|
|||
|
||||
@defexamples[
|
||||
(let ([curly 0])
|
||||
(begin
|
||||
(define moe (+ 1 curly))
|
||||
(define larry (+ 1 moe)))
|
||||
(list larry curly moe))
|
||||
(begin
|
||||
(define moe (+ 1 curly))
|
||||
(define larry (+ 1 moe)))
|
||||
(list larry curly moe))
|
||||
]
|
||||
|
||||
This splicing behavior is mainly useful for macros, as we discuss
|
||||
|
@ -114,13 +114,13 @@ result is @racket[#f].
|
|||
|
||||
@defexamples[
|
||||
(define (enumerate lst)
|
||||
(if (null? (cdr lst))
|
||||
(printf "~a.\n" (car lst))
|
||||
(begin
|
||||
(printf "~a, " (car lst))
|
||||
(when (null? (cdr (cdr lst)))
|
||||
(printf "and "))
|
||||
(enumerate (cdr lst)))))
|
||||
(if (null? (cdr lst))
|
||||
(printf "~a.\n" (car lst))
|
||||
(begin
|
||||
(printf "~a, " (car lst))
|
||||
(when (null? (cdr (cdr lst)))
|
||||
(printf "and "))
|
||||
(enumerate (cdr lst)))))
|
||||
(enumerate '("Larry" "Curly" "Moe"))
|
||||
]
|
||||
|
||||
|
|
|
@ -742,8 +742,8 @@ applied first. Then the method-implementing mixins can use
|
|||
(class % ....
|
||||
(define/public (get-color) (void))))
|
||||
(lambda (get-color get-price %) ....
|
||||
(class % ....
|
||||
(define/override (get-color) 'black))))
|
||||
(class % ....
|
||||
(define/override (get-color) 'black))))
|
||||
(list (local-member-name-key get-price)
|
||||
(lambda (get-price get-color %) ....
|
||||
(class % ....
|
||||
|
@ -752,7 +752,7 @@ applied first. Then the method-implementing mixins can use
|
|||
(class % ....
|
||||
(inherit get-color)
|
||||
(define/override (get-price)
|
||||
.... (get-color) ....))))))
|
||||
.... (get-color) ....))))))
|
||||
]
|
||||
|
||||
With this trait encoding, @racket[trait-alias] adds a new method with
|
||||
|
|
|
@ -60,9 +60,9 @@ racket
|
|||
[argmax
|
||||
(->i ([f (-> any/c real?)] [lov (and/c pair? list?)]) ()
|
||||
(r (f lov)
|
||||
(lambda (r)
|
||||
(define f@r (f r))
|
||||
(for/and ((v lov)) (>= f@r (f v))))))])
|
||||
(lambda (r)
|
||||
(define f@r (f r))
|
||||
(for/and ([v lov]) (>= f@r (f v))))))])
|
||||
]
|
||||
It is a @emph{dependent} contract that names the two arguments and uses
|
||||
the names to impose a predicate on the result. This predicate computes
|
||||
|
@ -84,9 +84,8 @@ racket
|
|||
(r (f lov)
|
||||
(lambda (r)
|
||||
(define f@r (f r))
|
||||
(and
|
||||
(memq r lov)
|
||||
(for/and ((v lov)) (>= f@r (f v)))))))])
|
||||
(and (memq r lov)
|
||||
(for/and ([v lov]) (>= f@r (f v)))))))])
|
||||
]
|
||||
The @racket[memq] function ensures that @racket[r] is @emph{intensionally equal}
|
||||
@margin-note*{That is, "pointer equality" for those who prefer to think at
|
||||
|
@ -113,7 +112,7 @@ racket
|
|||
(r (f lov)
|
||||
(lambda (r)
|
||||
(define f@r (f r))
|
||||
(and (for/and ((v lov)) (>= f@r (f v)))
|
||||
(and (for/and ([v lov]) (>= f@r (f v)))
|
||||
(eq? (first (memf (lambda (v) (= (f v) f@r)) lov))
|
||||
r)))))])
|
||||
]
|
||||
|
@ -157,7 +156,7 @@ racket
|
|||
|
||||
@code:comment{@#,dominates1}
|
||||
(define (dominates-all f@r f lov)
|
||||
(for/and ((v lov)) (>= (f v) f@r)))
|
||||
(for/and ([v lov]) (>= (f v) f@r)))
|
||||
|
||||
@code:comment{@#,first?1}
|
||||
(define (is-first-max? r f@r f lov)
|
||||
|
@ -199,7 +198,7 @@ racket
|
|||
|
||||
@code:comment{@#,dominates2}
|
||||
(define (dominates-all f@r flov)
|
||||
(for/and ((f@v flov)) (>= f@r f@v)))
|
||||
(for/and ([f@v flov]) (>= f@r f@v)))
|
||||
|
||||
@code:comment{@#,first?2}
|
||||
(define (is-first-max? r f@r lov+flov)
|
||||
|
|
|
@ -81,10 +81,9 @@ streams like this:
|
|||
@interaction[
|
||||
#:eval e
|
||||
(define stream/c
|
||||
(promise/c
|
||||
(or/c
|
||||
null?
|
||||
(cons/c number? stream/c))))
|
||||
(promise/c
|
||||
(or/c null?
|
||||
(cons/c number? stream/c))))
|
||||
]
|
||||
@close-eval[e]
|
||||
|
||||
|
@ -96,11 +95,10 @@ values that they accept do not.
|
|||
Instead, use
|
||||
@racketblock[
|
||||
(define stream/c
|
||||
(promise/c
|
||||
(or/c
|
||||
null?
|
||||
(cons/c 1
|
||||
(recursive-contract stream/c)))))
|
||||
(promise/c
|
||||
(or/c
|
||||
null?
|
||||
(cons/c 1 (recursive-contract stream/c)))))
|
||||
]
|
||||
|
||||
The use of @racket[recursive-contract] delays the evaluation of the
|
||||
|
|
|
@ -95,14 +95,14 @@ the requiring module, just to give an idea:
|
|||
|
||||
(module m racket
|
||||
(require mzlib/contract)
|
||||
(provide/contract [x x-ctc]))
|
||||
(provide/contract [x x-ctc]))
|
||||
|
||||
(module n racket (require m) (define (f) ... x ...))
|
||||
==>
|
||||
(module n racket
|
||||
(require (rename m x x-real))
|
||||
(define x (apply-contract x-real x-ctc ...))
|
||||
(define (f) ... x ...))
|
||||
(require (rename m x x-real))
|
||||
(define x (apply-contract x-real x-ctc ...))
|
||||
(define (f) ... x ...))
|
||||
|
||||
The intention is to only do the work of applying the
|
||||
contract once (per variable reference to a
|
||||
|
|
|
@ -261,7 +261,7 @@ resulting iteration can be performed more efficiently than plain
|
|||
@racket[for/vector] or @racket[for*/vector]:
|
||||
|
||||
@interaction[
|
||||
(let ((chapters '("Intro" "Details" "Conclusion")))
|
||||
(let ([chapters '("Intro" "Details" "Conclusion")])
|
||||
(for/vector #:length (length chapters) ([i (in-naturals 1)]
|
||||
[chapter chapters])
|
||||
(string-append (number->string i) ". " chapter)))
|
||||
|
|
|
@ -64,18 +64,18 @@ Consider the following core of a Mandelbrot-set computation:
|
|||
|
||||
@racketblock[
|
||||
(define (mandelbrot iterations x y n)
|
||||
(let ((ci (- (/ (* 2.0 y) n) 1.0))
|
||||
(cr (- (/ (* 2.0 x) n) 1.5)))
|
||||
(let loop ((i 0) (zr 0.0) (zi 0.0))
|
||||
(let ([ci (- (/ (* 2.0 y) n) 1.0)]
|
||||
[cr (- (/ (* 2.0 x) n) 1.5)])
|
||||
(let loop ([i 0] [zr 0.0] [zi 0.0])
|
||||
(if (> i iterations)
|
||||
i
|
||||
(let ((zrq (* zr zr))
|
||||
(ziq (* zi zi)))
|
||||
(let ([zrq (* zr zr)]
|
||||
[ziq (* zi zi)])
|
||||
(cond
|
||||
((> (+ zrq ziq) 4.0) i)
|
||||
(else (loop (add1 i)
|
||||
(+ (- zrq ziq) cr)
|
||||
(+ (* 2.0 zr zi) ci)))))))))
|
||||
[(> (+ zrq ziq) 4.0) i]
|
||||
[else (loop (add1 i)
|
||||
(+ (- zrq ziq) cr)
|
||||
(+ (* 2.0 zr zi) ci))]))))))
|
||||
]
|
||||
|
||||
The expressions @racket[(mandelbrot 10000000 62 500 1000)] and
|
||||
|
@ -110,8 +110,8 @@ first the problem:
|
|||
|
||||
@racketblock[
|
||||
(define (mandelbrot iterations x y n)
|
||||
(let ((ci (- (/ (* 2.0 (->fl y)) (->fl n)) 1.0))
|
||||
(cr (- (/ (* 2.0 (->fl x)) (->fl n)) 1.5)))
|
||||
(let ([ci (- (/ (* 2.0 (->fl y)) (->fl n)) 1.0)]
|
||||
[cr (- (/ (* 2.0 (->fl x)) (->fl n)) 1.5)])
|
||||
....))
|
||||
]
|
||||
|
||||
|
@ -128,18 +128,18 @@ much less allocation:
|
|||
|
||||
@racketblock[
|
||||
(define (mandelbrot iterations x y n)
|
||||
(let ((ci (fl- (fl/ (* 2.0 (->fl y)) (->fl n)) 1.0))
|
||||
(cr (fl- (fl/ (* 2.0 (->fl x)) (->fl n)) 1.5)))
|
||||
(let loop ((i 0) (zr 0.0) (zi 0.0))
|
||||
(let ([ci (fl- (fl/ (* 2.0 (->fl y)) (->fl n)) 1.0)]
|
||||
[cr (fl- (fl/ (* 2.0 (->fl x)) (->fl n)) 1.5)])
|
||||
(let loop ([i 0] [zr 0.0] [zi 0.0])
|
||||
(if (> i iterations)
|
||||
i
|
||||
(let ((zrq (fl* zr zr))
|
||||
(ziq (fl* zi zi)))
|
||||
(let ([zrq (fl* zr zr)]
|
||||
[ziq (fl* zi zi)])
|
||||
(cond
|
||||
((fl> (fl+ zrq ziq) 4.0) i)
|
||||
(else (loop (add1 i)
|
||||
(fl+ (fl- zrq ziq) cr)
|
||||
(fl+ (fl* 2.0 (fl* zr zi)) ci)))))))))
|
||||
[(fl> (fl+ zrq ziq) 4.0) i]
|
||||
[else (loop (add1 i)
|
||||
(fl+ (fl- zrq ziq) cr)
|
||||
(fl+ (fl* 2.0 (fl* zr zi)) ci))]))))))
|
||||
]
|
||||
|
||||
This conversion can speed @racket[mandelbrot] by a factor of 8, even
|
||||
|
|
|
@ -315,8 +315,8 @@ the source form are identifiers. We could use a
|
|||
(syntax-case stx ()
|
||||
[(rotate a c ...)
|
||||
(begin
|
||||
(check-ids stx #'(a c ...))
|
||||
#'(shift-to (c ... a) (a c ...)))]))
|
||||
(check-ids stx #'(a c ...))
|
||||
#'(shift-to (c ... a) (a c ...)))]))
|
||||
]
|
||||
|
||||
The @racket[check-ids] function can use the @racket[syntax->list]
|
||||
|
|
|
@ -217,13 +217,13 @@ racket
|
|||
(+ n 17))
|
||||
|
||||
(define-syntax (def-go stx)
|
||||
(syntax-case stx ()
|
||||
[(_ go)
|
||||
(protect-syntax
|
||||
#'(define-syntax (go stx)
|
||||
(syntax-case stx ()
|
||||
[(_ x)
|
||||
(protect-syntax #'(unchecked-go 8 x))])))]))
|
||||
(syntax-case stx ()
|
||||
[(_ go)
|
||||
(protect-syntax
|
||||
#'(define-syntax (go stx)
|
||||
(syntax-case stx ()
|
||||
[(_ x)
|
||||
(protect-syntax #'(unchecked-go 8 x))])))]))
|
||||
]
|
||||
|
||||
When @racket[def-go] is used inside another module to defined
|
||||
|
@ -247,13 +247,13 @@ racket
|
|||
(lambda (stx) (syntax-arm stx insp))))
|
||||
|
||||
(define-syntax (def-go stx)
|
||||
(syntax-case stx ()
|
||||
[(_ go)
|
||||
(protect-syntax
|
||||
#'(define-syntax (go stx)
|
||||
(syntax-case stx ()
|
||||
[(_ x)
|
||||
(go-syntax-protect #'(unchecked-go 8 x))])))]))
|
||||
(syntax-case stx ()
|
||||
[(_ go)
|
||||
(protect-syntax
|
||||
#'(define-syntax (go stx)
|
||||
(syntax-case stx ()
|
||||
[(_ x)
|
||||
(go-syntax-protect #'(unchecked-go 8 x))])))]))
|
||||
]
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
|
|
|
@ -313,28 +313,28 @@ racket
|
|||
|
||||
(define toy-store@-maker
|
||||
(lambda (the-color)
|
||||
(unit
|
||||
(import toy-factory^)
|
||||
(export toy-store^)
|
||||
(unit
|
||||
(import toy-factory^)
|
||||
(export toy-store^)
|
||||
|
||||
(define inventory null)
|
||||
(define inventory null)
|
||||
|
||||
(define (store-color) the-color)
|
||||
(define (store-color) the-color)
|
||||
|
||||
(code:comment @#,t{the rest is the same as before})
|
||||
(code:comment @#,t{the rest is the same as before})
|
||||
|
||||
(define (maybe-repaint t)
|
||||
(if (eq? (toy-color t) (store-color))
|
||||
t
|
||||
(repaint t (store-color))))
|
||||
(define (maybe-repaint t)
|
||||
(if (eq? (toy-color t) (store-color))
|
||||
t
|
||||
(repaint t (store-color))))
|
||||
|
||||
(define (stock! n)
|
||||
(set! inventory
|
||||
(append inventory
|
||||
(map maybe-repaint
|
||||
(build-toys n)))))
|
||||
(define (stock! n)
|
||||
(set! inventory
|
||||
(append inventory
|
||||
(map maybe-repaint
|
||||
(build-toys n)))))
|
||||
|
||||
(define (get-inventory) inventory))))
|
||||
(define (get-inventory) inventory))))
|
||||
|
||||
(provide toy-store@-maker)
|
||||
]
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
(only-in setup/infotab require)))
|
||||
|
||||
@(begin
|
||||
(define-syntax-rule (define-racket-require id)
|
||||
(begin
|
||||
(require (for-label (only-in racket require)))
|
||||
(define id @racket[require])))
|
||||
(define-racket-require racket:require))
|
||||
(define-syntax-rule (define-racket-require id)
|
||||
(begin
|
||||
(require (for-label (only-in racket require)))
|
||||
(define id @racket[require])))
|
||||
(define-racket-require racket:require))
|
||||
|
||||
@title[#:tag "info.rkt"]{@filepath{info.rkt} File Format}
|
||||
|
||||
|
|
|
@ -384,8 +384,8 @@ result will not call @racket[proc] with @racket['unlock].)
|
|||
(when ok-to-compile?
|
||||
(printf "Do compile here ...\n")))
|
||||
(lambda ()
|
||||
(when locked?
|
||||
(lc 'unlock zo-name)))))
|
||||
(when locked?
|
||||
(lc 'unlock zo-name)))))
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -27,12 +27,12 @@
|
|||
racket/future))
|
||||
|
||||
@(define-syntax-rule (local-module mod . body)
|
||||
(begin
|
||||
(define-syntax-rule (go)
|
||||
(begin
|
||||
(require (for-label mod))
|
||||
. body))
|
||||
(go)))
|
||||
(begin
|
||||
(define-syntax-rule (go)
|
||||
(begin
|
||||
(require (for-label mod))
|
||||
. body))
|
||||
(go)))
|
||||
|
||||
@(define ref-src
|
||||
'(lib "scribblings/reference/reference.scrbl"))
|
||||
|
|
|
@ -280,7 +280,8 @@ For communication among @tech{places}, the new byte string is allocated in the
|
|||
the other operations.
|
||||
@examples[
|
||||
(define b
|
||||
(bytes->string/utf-8 (bytes #xc3 #xa7 #xc3 #xb0 #xc3 #xb6 #xc2 #xa3)))
|
||||
(bytes->string/utf-8
|
||||
(bytes #xc3 #xa7 #xc3 #xb0 #xc3 #xb6 #xc2 #xa3)))
|
||||
|
||||
(string->bytes/utf-8 b)
|
||||
(bytes->string/utf-8 (string->bytes/utf-8 b))
|
||||
|
@ -316,7 +317,7 @@ For communication among @tech{places}, the new byte string is allocated in the
|
|||
|
||||
@examples[
|
||||
(define b
|
||||
(bytes->string/latin-1 (bytes #xfe #xd3 #xd1 #xa5)))
|
||||
(bytes->string/latin-1 (bytes #xfe #xd3 #xd1 #xa5)))
|
||||
|
||||
(string->bytes/latin-1 b)
|
||||
(bytes->string/latin-1 (string->bytes/latin-1 b))
|
||||
|
|
|
@ -12,15 +12,15 @@
|
|||
[(_ s ... s0) (elem (elem ", " (secref s)) ... ", and " (secref s0))]))
|
||||
|
||||
(define-syntax (defclassforms stx)
|
||||
(syntax-case stx (*)
|
||||
[(_ [* (form ...) (also ...)])
|
||||
#'(defform* (form ...)
|
||||
"See " @racket[class*] (sees also ...) "; use"
|
||||
" outside the body of a " @racket[class*] " form is a syntax error.")]
|
||||
[(_ [form (also ...)])
|
||||
#'(defclassforms [* (form) (also ...)])]
|
||||
[(_ form ...)
|
||||
#'(begin (defclassforms form) ...)]))
|
||||
(syntax-case stx (*)
|
||||
[(_ [* (form ...) (also ...)])
|
||||
#'(defform* (form ...)
|
||||
"See " @racket[class*] (sees also ...) "; use"
|
||||
" outside the body of a " @racket[class*] " form is a syntax error.")]
|
||||
[(_ [form (also ...)])
|
||||
#'(defclassforms [* (form) (also ...)])]
|
||||
[(_ form ...)
|
||||
#'(begin (defclassforms form) ...)]))
|
||||
|
||||
(define-syntax (defstarshorthands stx)
|
||||
(syntax-case stx ()
|
||||
|
@ -292,13 +292,13 @@ interface @racket[(class->interface object%)], and is transparent
|
|||
(lambda kw-formals expr ...+)
|
||||
(case-lambda (formals expr ...+) ...)
|
||||
(#%plain-lambda formals expr ...+)
|
||||
(let-values (((id) method-procedure) ...)
|
||||
(let-values ([(id) method-procedure] ...)
|
||||
method-procedure)
|
||||
(letrec-values (((id) method-procedure) ...)
|
||||
(letrec-values ([(id) method-procedure] ...)
|
||||
method-procedure)
|
||||
(let-values (((id) method-procedure) ...+)
|
||||
(let-values ([(id) method-procedure] ...+)
|
||||
id)
|
||||
(letrec-values (((id) method-procedure) ...+)
|
||||
(letrec-values ([(id) method-procedure] ...+)
|
||||
id)])]{
|
||||
|
||||
Produces a class value.
|
||||
|
@ -1366,11 +1366,11 @@ Produces a @tech{trait} that combines all of the methods of the given
|
|||
|
||||
@racketblock[
|
||||
(define t1
|
||||
(trait
|
||||
(define/public (m1) 1)))
|
||||
(trait
|
||||
(define/public (m1) 1)))
|
||||
(define t2
|
||||
(trait
|
||||
(define/public (m2) 2)))
|
||||
(trait
|
||||
(define/public (m2) 2)))
|
||||
(define t3 (trait-sum t1 t2))
|
||||
]
|
||||
|
||||
|
@ -1378,8 +1378,8 @@ creates a trait @racket[t3] that is equivalent to
|
|||
|
||||
@racketblock[
|
||||
(trait
|
||||
(define/public (m1) 1)
|
||||
(define/public (m2) 2))
|
||||
(define/public (m1) 1)
|
||||
(define/public (m2) 2))
|
||||
]
|
||||
|
||||
but @racket[t1] and @racket[t2] can still be used individually or
|
||||
|
|
|
@ -173,9 +173,9 @@ default error display handler (see
|
|||
|
||||
@examples[
|
||||
(define (extract-current-continuation-marks key)
|
||||
(continuation-mark-set->list
|
||||
(current-continuation-marks)
|
||||
key))
|
||||
(continuation-mark-set->list
|
||||
(current-continuation-marks)
|
||||
key))
|
||||
|
||||
(with-continuation-mark 'key 'mark
|
||||
(extract-current-continuation-marks 'key))
|
||||
|
|
|
@ -9,27 +9,27 @@
|
|||
|
||||
;; hacky?
|
||||
(define file-eval
|
||||
(lambda ()
|
||||
(let ([the-eval (make-base-eval)])
|
||||
(the-eval '(require (for-syntax racket/base)
|
||||
racket/file))
|
||||
(the-eval '(define some-file (make-temporary-file)))
|
||||
(the-eval '(define some-other-file (make-temporary-file)))
|
||||
the-eval)))
|
||||
(lambda ()
|
||||
(let ([the-eval (make-base-eval)])
|
||||
(the-eval '(require (for-syntax racket/base)
|
||||
racket/file))
|
||||
(the-eval '(define some-file (make-temporary-file)))
|
||||
(the-eval '(define some-other-file (make-temporary-file)))
|
||||
the-eval)))
|
||||
|
||||
(define-syntax file-examples
|
||||
(syntax-rules ()
|
||||
[(_ expr ...)
|
||||
(let [(my-eval (file-eval))]
|
||||
(define (clean)
|
||||
(my-eval '(for [(i (list some-file some-other-file))]
|
||||
(when (file-exists? i)
|
||||
(delete-file i)))))
|
||||
(clean)
|
||||
(begin0
|
||||
(defexamples #:eval my-eval
|
||||
expr ...)
|
||||
(clean)))]))
|
||||
(define (clean)
|
||||
(my-eval '(for [(i (list some-file some-other-file))]
|
||||
(when (file-exists? i)
|
||||
(delete-file i)))))
|
||||
(clean)
|
||||
(begin0
|
||||
(defexamples #:eval my-eval
|
||||
expr ...)
|
||||
(clean)))]))
|
||||
|
||||
"")
|
||||
|
||||
|
|
|
@ -196,4 +196,3 @@ For communication among @tech{places}, the new @tech{fxvector} is
|
|||
allocated in the @tech{shared memory space}.
|
||||
|
||||
@mz-examples[#:eval flfx-eval (make-shared-fxvector 4 3)]}
|
||||
|
||||
|
|
|
@ -144,8 +144,8 @@ is equivalent to
|
|||
@racketblock[
|
||||
(let ([l (current-logger)])
|
||||
(when (log-level? l '@#,racket[_level])
|
||||
(log-message l '@#,racket[_level] string-expr
|
||||
(current-continuation-marks))))
|
||||
(log-message l '@#,racket[_level] string-expr
|
||||
(current-continuation-marks))))
|
||||
]}
|
||||
|
||||
@; ----------------------------------------
|
||||
|
|
|
@ -481,7 +481,8 @@ instead of @racket[match].}
|
|||
type named @racket[struct-id], where the field @racket[field] in the
|
||||
instance matches the corresponding @racket[pat].
|
||||
|
||||
Any field of @racket[struct-id] may be omitted, and such fields can occur in any order.
|
||||
Any field of @racket[struct-id] may be omitted, and such fields can
|
||||
occur in any order.
|
||||
|
||||
@defexamples[
|
||||
#:eval match-eval
|
||||
|
|
|
@ -44,7 +44,7 @@ new parameter value. A guard procedure can raise an exception to
|
|||
reject a change to the parameter's value. The @racket[guard] is not
|
||||
applied to the initial @racket[v].}
|
||||
|
||||
@defform[(parameterize ((parameter-expr value-expr) ...)
|
||||
@defform[(parameterize ([parameter-expr value-expr] ...)
|
||||
body ...+)
|
||||
#:contracts
|
||||
([parameter-expr parameter?])]{
|
||||
|
|
|
@ -739,8 +739,8 @@ values from the generator.
|
|||
(if (null? x)
|
||||
0
|
||||
(begin
|
||||
(yield (car x))
|
||||
(loop (cdr x)))))))
|
||||
(yield (car x))
|
||||
(loop (cdr x)))))))
|
||||
(g)
|
||||
(g)
|
||||
(g)
|
||||
|
@ -812,8 +812,8 @@ Produces a @tech{sequence} that encapsulates the @tech{generator} formed by
|
|||
(if (null? x)
|
||||
my-stop-value
|
||||
(begin
|
||||
(yield (car x))
|
||||
(loop (cdr x)))))))
|
||||
(yield (car x))
|
||||
(loop (cdr x)))))))
|
||||
|
||||
(for/list ([i (in-producer my-generator my-stop-value)])
|
||||
i)]}
|
||||
|
|
|
@ -24,7 +24,7 @@ used as a macro that expands to a use of the target identifier, but
|
|||
@racket[syntax-local-value] of @racket[id] does not produce
|
||||
the target's value.}
|
||||
|
||||
@defform[(syntax-parameterize ((id expr) ...) body-expr ...+)]{
|
||||
@defform[(syntax-parameterize ([id expr] ...) body-expr ...+)]{
|
||||
|
||||
@margin-note/ref{See also @racket[splicing-syntax-parameterize].}
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ For example, the expression
|
|||
expands to
|
||||
|
||||
@racketblock[
|
||||
(let ((or-part x)) (if or-part or-part (or y)))
|
||||
(let ([or-part x]) (if or-part or-part (or y)))
|
||||
]
|
||||
|
||||
which, in turn, expands to
|
||||
|
|
|
@ -210,9 +210,9 @@ the binding (according to @racket[free-identifier=?]) matters.}
|
|||
(if expr expr expr)
|
||||
(begin expr ...+)
|
||||
(begin0 expr expr ...)
|
||||
(let-values (((id ...) expr) ...)
|
||||
(let-values ([(id ...) expr] ...)
|
||||
expr ...+)
|
||||
(letrec-values (((id ...) expr) ...)
|
||||
(letrec-values ([(id ...) expr] ...)
|
||||
expr ...+)
|
||||
(set! id expr)
|
||||
(@#,racket[quote] datum)
|
||||
|
@ -756,21 +756,21 @@ bucket-2
|
|||
(syntax-rules ()
|
||||
[(def-and-use)
|
||||
(begin
|
||||
(code:comment @#,t{Initial reference to @racket[even] precedes definition:})
|
||||
(define (odd x) (if (zero? x) #f (even (sub1 x))))
|
||||
(define (even x) (if (zero? x) #t (odd (sub1 x))))
|
||||
(odd 17))]))
|
||||
(code:comment @#,t{Initial reference to @racket[even] precedes definition:})
|
||||
(define (odd x) (if (zero? x) #f (even (sub1 x))))
|
||||
(define (even x) (if (zero? x) #t (odd (sub1 x))))
|
||||
(odd 17))]))
|
||||
(defs-and-uses/fail)
|
||||
|
||||
(define-syntax defs-and-uses
|
||||
(syntax-rules ()
|
||||
[(def-and-use)
|
||||
(begin
|
||||
(code:comment @#,t{Declare before definition via no-values @racket[define-syntaxes]:})
|
||||
(define-syntaxes (odd even) (values))
|
||||
(define (odd x) (if (zero? x) #f (even (sub1 x))))
|
||||
(define (even x) (if (zero? x) #t (odd (sub1 x))))
|
||||
(odd 17))]))
|
||||
(code:comment @#,t{Declare before definition via no-values @racket[define-syntaxes]:})
|
||||
(define-syntaxes (odd even) (values))
|
||||
(define (odd x) (if (zero? x) #f (even (sub1 x))))
|
||||
(define (even x) (if (zero? x) #t (odd (sub1 x))))
|
||||
(odd 17))]))
|
||||
(defs-and-uses)
|
||||
]
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ is prefixed with the special form name as described under
|
|||
|
||||
@examples[#:eval the-eval
|
||||
(wrong-syntax #'here "expected ~s" 'there)
|
||||
(parameterize ((current-syntax-context #'(look over here)))
|
||||
(parameterize ([current-syntax-context #'(look over here)])
|
||||
(wrong-syntax #'here "expected ~s" 'there))
|
||||
]
|
||||
|
||||
|
@ -117,7 +117,7 @@ A macro using @racket[wrong-syntax] might set the syntax context at the very
|
|||
beginning of its transformation as follows:
|
||||
@RACKETBLOCK[
|
||||
(define-syntax (my-macro stx)
|
||||
(parameterize ((current-syntax-context stx))
|
||||
(parameterize ([current-syntax-context stx])
|
||||
(syntax-case stx ()
|
||||
___)))
|
||||
]
|
||||
|
|
|
@ -905,18 +905,18 @@ follows.
|
|||
chickens))
|
||||
|
||||
(module nest2 racket
|
||||
(define-for-syntax eggs 2)
|
||||
(provide (for-syntax eggs)))
|
||||
(define-for-syntax eggs 2)
|
||||
(provide (for-syntax eggs)))
|
||||
(require (for-meta 2 racket/base)
|
||||
(for-syntax 'nest2))
|
||||
(define-syntax (test stx)
|
||||
(define-syntax (show-eggs stx)
|
||||
(printf "Eggs are ~a\n" eggs)
|
||||
#'0)
|
||||
(begin
|
||||
(show-eggs)
|
||||
#'0))
|
||||
(test)
|
||||
(define-syntax (show-eggs stx)
|
||||
(printf "Eggs are ~a\n" eggs)
|
||||
#'0)
|
||||
(begin
|
||||
(show-eggs)
|
||||
#'0))
|
||||
(test)
|
||||
]}
|
||||
|
||||
@specsubform[#:literals (for-syntax)
|
||||
|
@ -2144,8 +2144,8 @@ be defined by the same @racket[define-for-syntax] form.
|
|||
@defexamples[#:eval (syntax-eval)
|
||||
(define-for-syntax helper 2)
|
||||
(define-syntax (make-two syntax-object)
|
||||
(printf "helper is ~a\n" helper)
|
||||
#'2)
|
||||
(printf "helper is ~a\n" helper)
|
||||
#'2)
|
||||
(make-two)
|
||||
(code:comment @#,t{`helper' is not bound in the runtime phase})
|
||||
helper
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
@(define-syntax-rule (def base-author)
|
||||
(begin
|
||||
(require (for-label scribble/base))
|
||||
(define base-author @racket[author])))
|
||||
(require (for-label scribble/base))
|
||||
(define base-author @racket[author])))
|
||||
@(def base-author)
|
||||
|
||||
@title{JFP Paper Format}
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
@(define-syntax-rule (def base-author)
|
||||
(begin
|
||||
(require (for-label scribble/base))
|
||||
(define base-author @racket[author])))
|
||||
(require (for-label scribble/base))
|
||||
(define base-author @racket[author])))
|
||||
@(def base-author)
|
||||
|
||||
@title{LNCS Paper Format}
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
|
||||
@(begin
|
||||
(define-syntax-rule (def-render-mixin id)
|
||||
(begin
|
||||
(require (for-label scribble/html-render))
|
||||
(define id @racket[render-mixin])))
|
||||
(begin
|
||||
(require (for-label scribble/html-render))
|
||||
(define id @racket[render-mixin])))
|
||||
(def-render-mixin html:render-mixin))
|
||||
|
||||
@title[#:tag "renderer"]{Renderers}
|
||||
|
|
|
@ -117,8 +117,8 @@ form.}
|
|||
(->d (arg ...) () #:rest id rest [id result])])]{
|
||||
|
||||
Like @racket[proc-doc], but supporting contract forms that embed
|
||||
argument names. Only a subset of @racket[->i] and @racket[->d] forms are currently
|
||||
supported.}
|
||||
argument names. Only a subset of @racket[->i] and @racket[->d] forms are
|
||||
currently supported.}
|
||||
|
||||
@defform[(thing-doc id contract-expr dec-expr)]{
|
||||
|
||||
|
|
|
@ -163,7 +163,6 @@ Transfers cross-reference information to @racket[ci], which is the
|
|||
initially collected information from @racket[renderer].}
|
||||
|
||||
|
||||
|
||||
@defproc[(xref-index [xref xref?]) (listof entry?)]{
|
||||
|
||||
Converts indexing information @racket[xref] into a list of
|
||||
|
|
|
@ -83,12 +83,12 @@ language [*]:
|
|||
"#<procedure:closure-storing-proc>"
|
||||
(#%plain-lambda (x)
|
||||
(begin
|
||||
(let-values (((arg0-1643 arg1-1644 arg2-1645)
|
||||
(let-values ([(arg0-1643 arg1-1644 arg2-1645)
|
||||
(#%plain-app
|
||||
values
|
||||
"#<*unevaluated-struct*>"
|
||||
"#<*unevaluated-struct*>"
|
||||
"#<*unevaluated-struct*>")))
|
||||
"#<*unevaluated-struct*>")])
|
||||
(with-continuation-mark "#<debug-key-struct>"
|
||||
(#%plain-lambda ()
|
||||
(#%plain-app
|
||||
|
@ -161,7 +161,7 @@ language [*]:
|
|||
#f
|
||||
(#%plain-lambda () (#%plain-app list f))))))))
|
||||
|
||||
(let-values (((done-already?) (quote #f)))
|
||||
(let-values ([(done-already?) (quote #f)])
|
||||
(#%app dynamic-wind void
|
||||
(lambda () (#%app dynamic-require (quote (quote #%htdp)) (quote #f)))
|
||||
(lambda () (if done-already?
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
@(require "common.rkt" (for-label syntax/kerncase))
|
||||
|
||||
@(define-syntax-rule (intro id)
|
||||
(begin
|
||||
(require (for-label mzscheme))
|
||||
(define id (racket if))))
|
||||
(begin
|
||||
(require (for-label mzscheme))
|
||||
(define id (racket if))))
|
||||
@(intro mzscheme-if)
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
|
||||
@(begin
|
||||
(define the-eval
|
||||
(parameterize ((sandbox-output 'string)
|
||||
(sandbox-error-output 'string))
|
||||
(parameterize ([sandbox-output 'string]
|
||||
[sandbox-error-output 'string])
|
||||
(make-evaluator 'racket/base #:requires '(syntax/keyword))))
|
||||
;;(void (the-eval '(error-print-source-location #f)))
|
||||
(define-syntax-rule (myexamples e ...)
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
read-syntax-inside read-inside)))
|
||||
|
||||
@(begin
|
||||
(define-syntax-rule (define-mb name)
|
||||
(begin
|
||||
(require (for-label scheme/base))
|
||||
(define name @racket[#%module-begin])))
|
||||
(define-mb scheme-#%module-begin))
|
||||
(define-syntax-rule (define-mb name)
|
||||
(begin
|
||||
(require (for-label scheme/base))
|
||||
(define name @racket[#%module-begin])))
|
||||
(define-mb scheme-#%module-begin))
|
||||
|
||||
@(define guide-doc '(lib "scribblings/guide/guide.scrbl"))
|
||||
|
||||
|
|
|
@ -23,11 +23,11 @@ the parameter expressions.
|
|||
[(_ ((p v:expr) ...) body:expr)
|
||||
#:declare p (expr/c #'parameter?
|
||||
#:name "parameter argument")
|
||||
#'(parameterize ((p.c v) ...) body)]))
|
||||
(myparameterize ((current-input-port
|
||||
(open-input-string "(1 2 3)")))
|
||||
#'(parameterize ([p.c v] ...) body)]))
|
||||
(myparameterize ([current-input-port
|
||||
(open-input-string "(1 2 3)")])
|
||||
(read))
|
||||
(myparameterize (('whoops 'something))
|
||||
(myparameterize (['whoops 'something])
|
||||
'whatever)
|
||||
]
|
||||
|
||||
|
|
|
@ -425,7 +425,6 @@ They all construct a triangle oriented as follows:
|
|||
}
|
||||
|
||||
|
||||
|
||||
@defproc*[([(square [side-len (and/c real? (not/c negative?))]
|
||||
[mode mode?]
|
||||
[color image-color?])
|
||||
|
@ -657,7 +656,6 @@ the @racket[point-count] argument determines how many points the star has.
|
|||
(rectangle 40 40 "solid" "silver")
|
||||
(rectangle 50 50 "solid" "seagreen"))]
|
||||
|
||||
|
||||
}
|
||||
|
||||
@defproc[(overlay/offset [i1 image?] [x real?] [y real?] [i2 image?]) image?]{
|
||||
|
@ -777,7 +775,6 @@ the @racket[point-count] argument determines how many points the star has.
|
|||
(rectangle 30 30 50 "seagreen")
|
||||
(rectangle 20 20 50 "seagreen"))]
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -869,7 +866,6 @@ the @racket[point-count] argument determines how many points the star has.
|
|||
(ellipse 20 30 "solid" "dimgray")
|
||||
(ellipse 20 10 "solid" "black"))]
|
||||
|
||||
|
||||
}
|
||||
|
||||
@defproc[(beside/align [y-place y-place?] [i1 image?] [i2 image?] [is image?] ...) image?]{
|
||||
|
@ -894,7 +890,6 @@ the @racket[point-count] argument determines how many points the star has.
|
|||
(text "ijy" 18 "black")
|
||||
(text "ijy" 24 "black"))]
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -907,7 +902,6 @@ the @racket[point-count] argument determines how many points the star has.
|
|||
(ellipse 30 20 "solid" "dimgray")
|
||||
(ellipse 10 20 "solid" "black"))]
|
||||
|
||||
|
||||
}
|
||||
|
||||
@defproc[(above/align [x-place x-place?] [i1 image?] [i2 image?] [is image?] ...) image?]{
|
||||
|
@ -928,7 +922,6 @@ the @racket[point-count] argument determines how many points the star has.
|
|||
(ellipse 30 20 "solid" "darkolivegreen")
|
||||
(ellipse 10 20 "solid" "darkgreen"))]
|
||||
|
||||
|
||||
}
|
||||
|
||||
@section{Placing Images & Scenes}
|
||||
|
@ -937,11 +930,11 @@ Placing images into scenes is particularly useful when building worlds
|
|||
and universes using @racket[2htdp/universe].
|
||||
|
||||
@defproc*[([(empty-scene [width (and/c real? (not/c negative?))]
|
||||
[height (and/c real? (not/c negative?))])
|
||||
image?]
|
||||
[height (and/c real? (not/c negative?))])
|
||||
image?]
|
||||
[(empty-scene [width (and/c real? (not/c negative?))]
|
||||
[height (and/c real? (not/c negative?))]
|
||||
[color image-color?])
|
||||
[color image-color?])
|
||||
image?])]{
|
||||
|
||||
Creates an empty scene, i.e., a white rectangle with a black outline.
|
||||
|
@ -1201,9 +1194,10 @@ more expensive than with the other shapes.
|
|||
([bitmap-spec rel-string
|
||||
id])]{
|
||||
|
||||
Loads the bitmap specified by @racket[bitmap-spec]. If @racket[bitmap-spec] is a string, it is treated as a
|
||||
relative path. If it is an identifier, it is treated like a require spec and used to refer to a file
|
||||
in a collection.
|
||||
Loads the bitmap specified by @racket[bitmap-spec]. If
|
||||
@racket[bitmap-spec] is a string, it is treated as a relative path.
|
||||
If it is an identifier, it is treated like a require spec and used to
|
||||
refer to a file in a collection.
|
||||
|
||||
@image-examples[(bitmap icons/stop-16x16.png)
|
||||
(bitmap icons/b-run.png)]
|
||||
|
|
|
@ -197,35 +197,35 @@ The other big change concerns key event handling and mouse event
|
|||
@port[
|
||||
@racketblock[
|
||||
(define (change w a-key-event)
|
||||
(cond
|
||||
[(key=? a-key-event 'left)
|
||||
(world-go w -DELTA)]
|
||||
[(key=? a-key-event 'right)
|
||||
(world-go w +DELTA)]
|
||||
[(char? a-key-event)
|
||||
w]
|
||||
[(key=? a-key-event 'up)
|
||||
(world-go w -DELTA)]
|
||||
[(key=? a-key-event 'down)
|
||||
(world-go w +DELTA)]
|
||||
[else
|
||||
w]))]
|
||||
(cond
|
||||
[(key=? a-key-event 'left)
|
||||
(world-go w -DELTA)]
|
||||
[(key=? a-key-event 'right)
|
||||
(world-go w +DELTA)]
|
||||
[(char? a-key-event)
|
||||
w]
|
||||
[(key=? a-key-event 'up)
|
||||
(world-go w -DELTA)]
|
||||
[(key=? a-key-event 'down)
|
||||
(world-go w +DELTA)]
|
||||
[else
|
||||
w]))]
|
||||
@; ---------------------------------
|
||||
@racketblock[
|
||||
(define (change w a-key-event)
|
||||
(cond
|
||||
[(key=? a-key-event "left")
|
||||
(world-go w -DELTA)]
|
||||
[(key=? a-key-event "right")
|
||||
(world-go w +DELTA)]
|
||||
[(= (string-length a-key-event) 1)
|
||||
w]
|
||||
[(key=? a-key-event "up")
|
||||
(world-go w -DELTA)]
|
||||
[(key=? a-key-event "down")
|
||||
(world-go w +DELTA)]
|
||||
[else
|
||||
w]))
|
||||
(cond
|
||||
[(key=? a-key-event "left")
|
||||
(world-go w -DELTA)]
|
||||
[(key=? a-key-event "right")
|
||||
(world-go w +DELTA)]
|
||||
[(= (string-length a-key-event) 1)
|
||||
w]
|
||||
[(key=? a-key-event "up")
|
||||
(world-go w -DELTA)]
|
||||
[(key=? a-key-event "down")
|
||||
(world-go w +DELTA)]
|
||||
[else
|
||||
w]))
|
||||
]]
|
||||
Note how the @racket[char?] clause changed. Since all chars are now
|
||||
represented as strings containing one ``letter'', the program on the right
|
||||
|
|
|
@ -29,16 +29,15 @@ Example:
|
|||
(racketblock
|
||||
;; Advanced
|
||||
(define (make-model dir)
|
||||
(lambda (b e)
|
||||
(begin
|
||||
(view dir)
|
||||
(printf "~a ~n" (control)))))
|
||||
(lambda (b e)
|
||||
(begin
|
||||
(view dir)
|
||||
(printf "~a ~n" (control)))))
|
||||
|
||||
(connect
|
||||
(make-model "left")
|
||||
(make-model "right")
|
||||
(make-model "up")
|
||||
(make-model "down"))
|
||||
(connect (make-model "left")
|
||||
(make-model "right")
|
||||
(make-model "up")
|
||||
(make-model "down"))
|
||||
))
|
||||
Now click on the four arrows. The message field contains the current
|
||||
direction, the print-out the prior contents of the message field.
|
||||
|
|
|
@ -83,10 +83,10 @@ Example 2:
|
|||
;; a text field, a message, and two buttons
|
||||
;; fill in text and click OKAY
|
||||
(define w
|
||||
(create-window
|
||||
(list
|
||||
(list text1)
|
||||
(list msg1)
|
||||
(list (make-button "OKAY" respond)
|
||||
(make-button "QUIT" (lambda (e) (hide-window w)))))))
|
||||
(create-window
|
||||
(list
|
||||
(list text1)
|
||||
(list msg1)
|
||||
(list (make-button "OKAY" respond)
|
||||
(make-button "QUIT" (lambda (e) (hide-window w)))))))
|
||||
))
|
||||
|
|
|
@ -34,22 +34,27 @@ This module provides a macro for regular expression compilation.
|
|||
pat])]{
|
||||
Compiles a regular expression over match patterns to a @racket[machine].
|
||||
|
||||
The interpretation of the pattern language is mostly intuitive. The pattern language may be extended
|
||||
with @racket[define-re-transformer]. @racket[dseq] allows bindings of the @racket[match] pattern to be
|
||||
used in the rest of the regular expression. (Thus, they are not @emph{really} regular expressions.)
|
||||
@racket[unquote] escapes to Racket to evaluate an expression that evaluates to a regular expression (this happens
|
||||
once, at compile time.) @racket[rec] binds a Racket identifier to a delayed version of the inner expression; even
|
||||
if the expression is initially accepting, this delayed version is never accepting.
|
||||
The interpretation of the pattern language is mostly intuitive. The
|
||||
pattern language may be extended with @racket[define-re-transformer].
|
||||
@racket[dseq] allows bindings of the @racket[match] pattern to be used
|
||||
in the rest of the regular expression. (Thus, they are not
|
||||
@emph{really} regular expressions.) @racket[unquote] escapes to Racket
|
||||
to evaluate an expression that evaluates to a regular expression (this
|
||||
happens once, at compile time.) @racket[rec] binds a Racket identifier
|
||||
to a delayed version of the inner expression; even if the expression is
|
||||
initially accepting, this delayed version is never accepting.
|
||||
|
||||
The compiler will use an NFA, provided @racket[complement] and @racket[dseq] are not used. Otherwise,
|
||||
many NFAs connected with the machine simulation functions from @racketmodname[unstable/automata/machine] are used.
|
||||
The compiler will use an NFA, provided @racket[complement] and
|
||||
@racket[dseq] are not used. Otherwise, many NFAs connected with the
|
||||
machine simulation functions from
|
||||
@racketmodname[unstable/automata/machine] are used.
|
||||
}
|
||||
|
||||
@(define-syntax-rule (defidforms (id ...) . dat)
|
||||
(deftogether ((defidform id) ...) . dat))
|
||||
|
||||
@defidforms[(complement seq union star epsilon nullset dseq rec)]{
|
||||
Bindings for use in @racket[re].
|
||||
Bindings for use in @racket[re].
|
||||
}
|
||||
|
||||
@defform[(define-re-transformer id expr)]{
|
||||
|
@ -127,9 +132,9 @@ This module provides a few transformers that extend the syntax of regular expres
|
|||
[(list "B")])
|
||||
|
||||
(define-re-transformer my-opt
|
||||
(syntax-rules ()
|
||||
[(_ pat)
|
||||
(union epsilon pat)]))
|
||||
(syntax-rules ()
|
||||
[(_ pat)
|
||||
(union epsilon pat)]))
|
||||
|
||||
(test-re (my-opt "A")
|
||||
[(list)
|
||||
|
|
|
@ -24,18 +24,26 @@
|
|||
[name? identifier?]
|
||||
[method identifier?])]{
|
||||
|
||||
Defines @racket[name] as a transformer binding for the static information about a new generic group.
|
||||
Defines @racket[name] as a transformer binding for the static
|
||||
information about a new generic group.
|
||||
|
||||
Defines @racket[prop:name] as a structure
|
||||
type property. Structure types implementing this generic group should have this property where the value is a vector
|
||||
with one element per @racket[method] where each value is
|
||||
either @racket[#f] or a procedure with the same arity as specified by @racket[kw-formals*].
|
||||
(@racket[kw-formals*] is similar to the @racket[kw-formals] used by @racket[lambda], except no expression is given for optional arguments.)
|
||||
The arity of each method is checked by the guard on the structure type property.
|
||||
Defines @racket[prop:name] as a structure type property. Structure
|
||||
types implementing this generic group should have this property where
|
||||
the value is a vector with one element per @racket[method] where each
|
||||
value is either @racket[#f] or a procedure with the same arity as
|
||||
specified by @racket[kw-formals*]. (@racket[kw-formals*] is similar to
|
||||
the @racket[kw-formals] used by @racket[lambda], except no expression is
|
||||
given for optional arguments.) The arity of each method is checked by
|
||||
the guard on the structure type property.
|
||||
|
||||
Defines @racket[name?] as a predicate identifying instances of structure types that implement this generic group.
|
||||
Defines @racket[name?] as a predicate identifying instances of structure
|
||||
types that implement this generic group.
|
||||
|
||||
Defines each @racket[method] as a generic procedure that calls the corresponding method on values where @racket[name?] is true. Each method must have a required by-position argument that is @racket[free-identifier=?] to @racket[name]. This argument is used in the generic definition to locate the specialization.
|
||||
Defines each @racket[method] as a generic procedure that calls the
|
||||
corresponding method on values where @racket[name?] is true. Each method
|
||||
must have a required by-position argument that is
|
||||
@racket[free-identifier=?] to @racket[name]. This argument is used in
|
||||
the generic definition to locate the specialization.
|
||||
|
||||
}
|
||||
|
||||
|
@ -61,13 +69,18 @@ context of @racket[name].
|
|||
#:contracts
|
||||
([name identifier?])]{
|
||||
|
||||
@racket[name] must be a transformer binding for the static information about a new generic group.
|
||||
@racket[name] must be a transformer binding for the static information
|
||||
about a new generic group.
|
||||
|
||||
Expands to a value usable as the property value for the structure type property of the @racket[name] generic group.
|
||||
Expands to a value usable as the property value for the structure type
|
||||
property of the @racket[name] generic group.
|
||||
|
||||
If the @racket[definition]s define the methods of @racket[name], then they are used in the property value.
|
||||
If the @racket[definition]s define the methods of @racket[name], then
|
||||
they are used in the property value.
|
||||
|
||||
If any method of @racket[name] is not defined, then @racket[#f] is used to signify that the structure type does not implement the particular method.
|
||||
If any method of @racket[name] is not defined, then @racket[#f] is used
|
||||
to signify that the structure type does not implement the particular
|
||||
method.
|
||||
|
||||
Allows @racket[define/generic] to appear in @racket[definition ...].
|
||||
|
||||
|
@ -78,7 +91,9 @@ Allows @racket[define/generic] to appear in @racket[definition ...].
|
|||
([local-name identifier?]
|
||||
[method-name identifier?])]{
|
||||
|
||||
When used inside @racket[define-methods], binds @racket[local-name] to the generic for @racket[method-name]. This is useful for method specializations to use the generic methods on other values.
|
||||
When used inside @racket[define-methods], binds @racket[local-name] to
|
||||
the generic for @racket[method-name]. This is useful for method
|
||||
specializations to use the generic methods on other values.
|
||||
|
||||
Syntactically an error when used outside @racket[define-methods].
|
||||
|
||||
|
|
|
@ -29,9 +29,18 @@ This library provides a simplified version of parameters that are backed by cont
|
|||
[none-v [any/c #f]]
|
||||
[tag continuation-prompt-tag? default-continuation-prompt-tag])
|
||||
(listof vector?)]{
|
||||
Returns the values of the @racket[mps] up to @racket[tag]. The length of each vector in the result list is the same as the length of @racket[mps], and a value in a particular vector position is the value for the corresponding mark parameter in @racket[mps]. Values for multiple mark parameter appear in a single vector only when the mark parameters are for the same continuation frame in the current continuation. The @racket[none-v] argument is used for vector elements to indicate the lack of a value.
|
||||
}
|
||||
Returns the values of the @racket[mps] up to @racket[tag]. The length
|
||||
of each vector in the result list is the same as the length of
|
||||
@racket[mps], and a value in a particular vector position is the value
|
||||
for the corresponding mark parameter in @racket[mps]. Values for
|
||||
multiple mark parameter appear in a single vector only when the mark
|
||||
parameters are for the same continuation frame in the current
|
||||
continuation. The @racket[none-v] argument is used for vector elements
|
||||
to indicate the lack of a value.
|
||||
}
|
||||
|
||||
@defform[(mark-parameterize ([mp expr] ...) body-expr ...)]{
|
||||
Parameterizes @racket[(begin body-expr ...)] by associating each @racket[mp] with the evaluation of @racket[expr] in the parameterization of the entire expression.
|
||||
}
|
||||
Parameterizes @racket[(begin body-expr ...)] by associating each
|
||||
@racket[mp] with the evaluation of @racket[expr] in the
|
||||
parameterization of the entire expression.
|
||||
}
|
||||
|
|
|
@ -40,16 +40,16 @@ The other arguments have the same meaning as for @racket[expr/c].
|
|||
@examples[#:eval the-eval
|
||||
(define-syntax (myparameterize1 stx)
|
||||
(syntax-case stx ()
|
||||
[(_ ((p v)) body)
|
||||
[(_ ([p v]) body)
|
||||
(with-syntax ([cp (wrap-expr/c
|
||||
#'parameter? #'p
|
||||
#:name "the parameter argument"
|
||||
#:context stx)])
|
||||
#'(parameterize ((cp v)) body))]))
|
||||
(myparameterize1 ((current-input-port
|
||||
(open-input-string "(1 2 3)")))
|
||||
#'(parameterize ([cp v]) body))]))
|
||||
(myparameterize1 ([current-input-port
|
||||
(open-input-string "(1 2 3)")])
|
||||
(read))
|
||||
(myparameterize1 (('whoops 'something))
|
||||
(myparameterize1 (['whoops 'something])
|
||||
'whatever)
|
||||
|
||||
(module mod racket
|
||||
|
|
|
@ -7,18 +7,19 @@
|
|||
web-server/lang/serial-lambda
|
||||
web-server/private/define-closure))
|
||||
|
||||
|
||||
The defunctionalization process of the Web Language (see @secref["stateless" #:doc '(lib "web-server/scribblings/web-server.scrbl")])
|
||||
The defunctionalization process of the Web Language (see
|
||||
@secref["stateless" #:doc '(lib "web-server/scribblings/web-server.scrbl")])
|
||||
requires an explicit representation of closures that is serializable.
|
||||
|
||||
@defmodule[web-server/lang/serial-lambda]{
|
||||
|
||||
@defform[(serial-lambda formals body ...)]{
|
||||
Returns @racket[(lambda formals body ...)], except it is serializable.
|
||||
Returns @racket[(lambda formals body ...)], except it is serializable.
|
||||
}
|
||||
|
||||
@defform[(serial-case-lambda [formals body ...] ...)]{
|
||||
Returns @racket[(case-lambda [formals body ...] ...)], except it is serializable.
|
||||
Returns @racket[(case-lambda [formals body ...] ...)], except it is
|
||||
serializable.
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,9 +20,10 @@
|
|||
[path->serlvet path->servlet/c])
|
||||
(values (-> void)
|
||||
url->servlet/c)]{
|
||||
The first return value flushes the cache.
|
||||
The second is a procedure that uses @racket[url->path] to resolve the URL to a path, then uses @racket[path->servlet] to resolve
|
||||
that path to a servlet, caching the results in an internal table.
|
||||
The first return value flushes the cache. The second is a procedure
|
||||
that uses @racket[url->path] to resolve the URL to a path, then uses
|
||||
@racket[path->servlet] to resolve that path to a servlet, caching the
|
||||
results in an internal table.
|
||||
}
|
||||
|
||||
@defproc[(make [url->servlet url->servlet/c]
|
||||
|
@ -35,9 +36,12 @@
|
|||
(url? exn? . -> . can-be-response?)
|
||||
servlet-error-responder])
|
||||
dispatcher/c]{
|
||||
This dispatcher runs racket servlets, using @racket[url->servlet] to resolve URLs to the underlying servlets.
|
||||
If servlets have errors loading, then @racket[responders-servlet-loading] is used. Other errors are handled with
|
||||
@racket[responders-servlet]. If a servlet raises calls @racket[next-dispatcher], then the signal is propagated by this dispatcher.
|
||||
This dispatcher runs racket servlets, using @racket[url->servlet] to
|
||||
resolve URLs to the underlying servlets. If servlets have errors
|
||||
loading, then @racket[responders-servlet-loading] is used. Other errors
|
||||
are handled with @racket[responders-servlet]. If a servlet raises calls
|
||||
@racket[next-dispatcher], then the signal is propagated by this
|
||||
dispatcher.
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -49,17 +53,17 @@
|
|||
@section{Internal Servlet Representation}
|
||||
|
||||
@defmodule[web-server/private/servlet]{
|
||||
@defstruct[servlet ([custodian custodian?]
|
||||
[namespace namespace?]
|
||||
[manager manager?]
|
||||
[directory path-string?]
|
||||
[handler (request? . -> . can-be-response?)])
|
||||
#:mutable]{
|
||||
Instances of this structure hold the necessary parts of a servlet:
|
||||
the @racket[custodian] responsible for the servlet's resources,
|
||||
the @racket[namespace] the servlet is executed within,
|
||||
the @racket[manager] responsible for the servlet's continuations,
|
||||
the current @racket[directory] of the servlet,
|
||||
and the @racket[handler] for all requests to the servlet.
|
||||
}
|
||||
@defstruct[servlet ([custodian custodian?]
|
||||
[namespace namespace?]
|
||||
[manager manager?]
|
||||
[directory path-string?]
|
||||
[handler (request? . -> . can-be-response?)])
|
||||
#:mutable]{
|
||||
Instances of this structure hold the necessary parts of a servlet:
|
||||
the @racket[custodian] responsible for the servlet's resources,
|
||||
the @racket[namespace] the servlet is executed within,
|
||||
the @racket[manager] responsible for the servlet's continuations,
|
||||
the current @racket[directory] of the servlet,
|
||||
and the @racket[handler] for all requests to the servlet.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,10 +102,12 @@ URLs to paths on the filesystem.
|
|||
@defproc[(filter-url->path [regex regexp?]
|
||||
[url->path url->path/c])
|
||||
url->path/c]{
|
||||
Runs the underlying @racket[url->path] but will only return if the path, when considered as a string,
|
||||
matches the @racket[regex]. This is useful to disallow strange files, like GIFs, from being considered
|
||||
servlets when using the servlet dispatchers. It will return a @racket[exn:fail:filesystem:exists?] exception if
|
||||
the path does not match.
|
||||
Runs the underlying @racket[url->path] but will only return if the
|
||||
path, when considered as a string, matches the @racket[regex]. This is
|
||||
useful to disallow strange files, like GIFs, from being considered
|
||||
servlets when using the servlet dispatchers. It will return a
|
||||
@racket[exn:fail:filesystem:exists?] exception if the path does not
|
||||
match.
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -249,9 +251,9 @@ a URL that refreshes the password file, servlet cache, etc.}
|
|||
web-server/configuration/responders))
|
||||
|
||||
@defthing[denied?/c contract?]{
|
||||
Equivalent to @racket[(request? . -> . (or/c false/c string?))].
|
||||
The return is the authentication realm as a string if the request is not authorized and
|
||||
@racket[#f] if the request @emph{is} authorized.
|
||||
Equivalent to @racket[(request? . -> . (or/c false/c string?))]. The
|
||||
return is the authentication realm as a string if the request is not
|
||||
authorized and @racket[#f] if the request @emph{is} authorized.
|
||||
}
|
||||
|
||||
@defproc[(make [denied? denied?/c]
|
||||
|
@ -260,24 +262,26 @@ a URL that refreshes the password file, servlet cache, etc.}
|
|||
(url? header? . -> . response?)
|
||||
(gen-authentication-responder "forbidden.html")])
|
||||
dispatcher/c]{
|
||||
A dispatcher that checks if the request is denied based on @racket[denied?]. If so, then
|
||||
@racket[authentication-responder] is called with a @racket[header] that
|
||||
requests credentials. If not, then @racket[next-dispatcher] is
|
||||
invoked.
|
||||
A dispatcher that checks if the request is denied based on
|
||||
@racket[denied?]. If so, then @racket[authentication-responder] is
|
||||
called with a @racket[header] that requests credentials. If not, then
|
||||
@racket[next-dispatcher] is invoked.
|
||||
}
|
||||
|
||||
@defthing[authorized?/c contract?]{
|
||||
Equivalent to @racket[(string? (or/c false/c bytes?) (or/c false/c bytes?) . -> . (or/c false/c string?))].
|
||||
The input is the URI as a string and the username and passwords as bytes.
|
||||
The return is the authentication realm as a string if the user is not authorized and
|
||||
@racket[#f] if the request @emph{is} authorized.
|
||||
Equivalent to
|
||||
@racket[(string? (or/c false/c bytes?) (or/c false/c bytes?) . -> . (or/c false/c string?))].
|
||||
The input is the URI as a string and the username and passwords as
|
||||
bytes. The return is the authentication realm as a string if the user
|
||||
is not authorized and @racket[#f] if the request @emph{is} authorized.
|
||||
}
|
||||
|
||||
@defproc[(make-basic-denied?/path [password-file path-string?])
|
||||
(values (-> void)
|
||||
authorized?/c)]{
|
||||
Creates an authorization procedure based on the given password file. The first returned value
|
||||
is a procedure that refreshes the password cache used by the authorization procedure.
|
||||
Creates an authorization procedure based on the given password
|
||||
file. The first returned value is a procedure that refreshes the
|
||||
password cache used by the authorization procedure.
|
||||
|
||||
@racket[password-file] is parsed as:
|
||||
@racketblock[(list ([domain : string?]
|
||||
|
|
|
@ -23,9 +23,8 @@ Suppose we want to create an abstraction of entering a date in an HTML form. The
|
|||
@racketblock[
|
||||
(define date-formlet
|
||||
(formlet
|
||||
(div
|
||||
"Month:" ,{input-int . => . month}
|
||||
"Day:" ,{input-int . => . day})
|
||||
(div "Month:" ,{input-int . => . month}
|
||||
"Day:" ,{input-int . => . day})
|
||||
(list month day)))
|
||||
]
|
||||
|
||||
|
@ -233,36 +232,39 @@ types. Refer to @secref["input-formlets"] for example low-level formlets using t
|
|||
|
||||
@defproc[(xml-forest [r xexpr-forest/c])
|
||||
(formlet/c procedure?)]{
|
||||
Constructs a @tech{formlet} with the rendering @racket[r] and the identity procedure as the processing step.
|
||||
Constructs a @tech{formlet} with the rendering @racket[r] and the
|
||||
identity procedure as the processing step.
|
||||
}
|
||||
|
||||
@defproc[(xml [r xexpr/c])
|
||||
(formlet/c procedure?)]{
|
||||
Equivalent to @racket[(xml-forest (list r))].
|
||||
Equivalent to @racket[(xml-forest (list r))].
|
||||
}
|
||||
|
||||
@defproc[(text [r string?])
|
||||
(formlet/c procedure?)]{
|
||||
Equivalent to @racket[(xml r)].
|
||||
Equivalent to @racket[(xml r)].
|
||||
}
|
||||
|
||||
@defproc[(tag-xexpr [tag symbol?]
|
||||
[attrs (listof (list/c symbol? string?))]
|
||||
[inner (formlet/c any/c)])
|
||||
(formlet/c any/c)]{
|
||||
Constructs a @tech{formlet} with the rendering @racket[(list (list* tag attrs inner-rendering))] where @racket[inner-rendering] is
|
||||
the rendering of @racket[inner] and the processing stage identical to @racket[inner].
|
||||
Constructs a @tech{formlet} with the rendering @racket[(list (list*
|
||||
tag attrs inner-rendering))] where @racket[inner-rendering] is the
|
||||
rendering of @racket[inner] and the processing stage identical to
|
||||
@racket[inner].
|
||||
}
|
||||
|
||||
@defproc[(formlet-display [f (formlet/c any/c)])
|
||||
xexpr-forest/c]{
|
||||
Renders @racket[f].
|
||||
Renders @racket[f].
|
||||
}
|
||||
|
||||
@defproc[(formlet-process [f (formlet/c any/c ...)]
|
||||
[r request?])
|
||||
(values any/c ...)]{
|
||||
Runs the processing stage of @racket[f] on the bindings in @racket[r].
|
||||
Runs the processing stage of @racket[f] on the bindings in @racket[r].
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -276,14 +278,15 @@ These @tech{formlet}s are the main combinators for form input.
|
|||
|
||||
@defproc[(make-input [render (string? . -> . xexpr/c)])
|
||||
(formlet/c (or/c false/c binding?))]{
|
||||
This @tech{formlet} is rendered with @racket[render], which is passed the input name, and results in the
|
||||
extracted @racket[binding].
|
||||
This @tech{formlet} is rendered with @racket[render], which is passed
|
||||
the input name, and results in the extracted @racket[binding].
|
||||
}
|
||||
|
||||
@defproc[(make-input* [render (string? . -> . xexpr/c)])
|
||||
(formlet/c (listof binding?))]{
|
||||
This @tech{formlet} is rendered with @racket[render], which is passed the input name, and results in all the
|
||||
@racket[binding]s that use the name.
|
||||
This @tech{formlet} is rendered with @racket[render], which is passed
|
||||
the input name, and results in all the @racket[binding]s that use the
|
||||
name.
|
||||
}
|
||||
|
||||
@defproc[(text-input [#:value value (or/c false/c bytes?) #f]
|
||||
|
@ -292,7 +295,8 @@ These @tech{formlet}s are the main combinators for form input.
|
|||
[#:read-only? read-only? boolean? #f]
|
||||
[#:attributes attrs (listof (list/c symbol? string?)) empty])
|
||||
(formlet/c (or/c false/c binding?))]{
|
||||
This @tech{formlet} renders using an INPUT element with the TEXT type and the attributes given in the arguments.
|
||||
This @tech{formlet} renders using an INPUT element with the TEXT type
|
||||
and the attributes given in the arguments.
|
||||
}
|
||||
|
||||
@defproc[(password-input [#:value value (or/c false/c bytes?) #f]
|
||||
|
@ -301,7 +305,8 @@ These @tech{formlet}s are the main combinators for form input.
|
|||
[#:read-only? read-only? boolean? #f]
|
||||
[#:attributes attrs (listof (list/c symbol? string?)) empty])
|
||||
(formlet/c (or/c false/c binding?))]{
|
||||
This @tech{formlet} renders using an INPUT element with the PASSWORD type and the attributes given in the arguments.
|
||||
This @tech{formlet} renders using an INPUT element with the PASSWORD
|
||||
type and the attributes given in the arguments.
|
||||
}
|
||||
|
||||
@defproc[(textarea-input [#:value value (or/c false/c bytes?) #f]
|
||||
|
@ -309,14 +314,16 @@ These @tech{formlet}s are the main combinators for form input.
|
|||
[#:cols cols (or/c false/c number?) #f]
|
||||
[#:attributes attrs (listof (list/c symbol? string?)) empty])
|
||||
(formlet/c (or/c false/c binding?))]{
|
||||
This @tech{formlet} renders using an TEXTAREA element with attributes given in the arguments.
|
||||
This @tech{formlet} renders using an TEXTAREA element with attributes
|
||||
given in the arguments.
|
||||
}
|
||||
|
||||
@defproc[(checkbox [value bytes?]
|
||||
[checked? boolean?]
|
||||
[#:attributes attrs (listof (list/c symbol? string?)) empty])
|
||||
(formlet/c (or/c false/c binding?))]{
|
||||
This @tech{formlet} renders using an INPUT element with the CHECKBOX type and the attributes given in the arguments.
|
||||
This @tech{formlet} renders using an INPUT element with the CHECKBOX
|
||||
type and the attributes given in the arguments.
|
||||
}
|
||||
|
||||
@defproc[(radio [value bytes?]
|
||||
|
@ -329,23 +336,27 @@ These @tech{formlet}s are the main combinators for form input.
|
|||
@defproc[(submit [value bytes?]
|
||||
[#:attributes attrs (listof (list/c symbol? string?)) empty])
|
||||
(formlet/c (or/c false/c binding?))]{
|
||||
This @tech{formlet} renders using an INPUT element with the SUBMIT type and the attributes given in the arguments.
|
||||
This @tech{formlet} renders using an INPUT element with the SUBMIT
|
||||
type and the attributes given in the arguments.
|
||||
}
|
||||
|
||||
@defproc[(reset [value bytes?]
|
||||
[#:attributes attrs (listof (list/c symbol? string?)) empty])
|
||||
(formlet/c (or/c false/c binding?))]{
|
||||
This @tech{formlet} renders using an INPUT element with the RESET type and the attributes given in the arguments.
|
||||
This @tech{formlet} renders using an INPUT element with the RESET type
|
||||
and the attributes given in the arguments.
|
||||
}
|
||||
|
||||
@defproc[(file-upload [#:attributes attrs (listof (list/c symbol? string?)) empty])
|
||||
(formlet/c (or/c false/c binding?))]{
|
||||
This @tech{formlet} renders using an INPUT element with the FILE type and the attributes given in the arguments.
|
||||
This @tech{formlet} renders using an INPUT element with the FILE type
|
||||
and the attributes given in the arguments.
|
||||
}
|
||||
|
||||
@defproc[(hidden [value bytes?] [#:attributes attrs (listof (list/c symbol? string?)) empty])
|
||||
(formlet/c (or/c false/c binding?))]{
|
||||
This @tech{formlet} renders using an INPUT element with HIDDEN type and the attributes given in the arguments.
|
||||
This @tech{formlet} renders using an INPUT element with HIDDEN type
|
||||
and the attributes given in the arguments.
|
||||
}
|
||||
|
||||
@defproc[(img [alt bytes?]
|
||||
|
@ -356,7 +367,8 @@ These @tech{formlet}s are the main combinators for form input.
|
|||
[#:width width (or/c false/c exact-nonnegative-integer?) #f]
|
||||
[#:attributes attrs (listof (list/c symbol? string?)) empty])
|
||||
(formlet/c (or/c false/c binding?))]{
|
||||
This @tech{formlet} renders using an IMG element with the attributes given in the arguments.
|
||||
This @tech{formlet} renders using an IMG element with the attributes
|
||||
given in the arguments.
|
||||
}
|
||||
|
||||
@defproc[(button [type bytes?]
|
||||
|
@ -365,7 +377,9 @@ These @tech{formlet}s are the main combinators for form input.
|
|||
[#:value value (or/c false/c bytes?) #f]
|
||||
[#:attributes attrs (listof (list/c symbol? string?)) empty])
|
||||
(formlet/c (or/c false/c binding?))]{
|
||||
This @tech{formlet} renders using a BUTTON element with the attributes given in the arguments. @racket[button-text] is the text that will appear on the button when rendered.
|
||||
This @tech{formlet} renders using a BUTTON element with the attributes
|
||||
given in the arguments. @racket[button-text] is the text that will
|
||||
appear on the button when rendered.
|
||||
}
|
||||
|
||||
@defproc[(multiselect-input [l sequence?]
|
||||
|
@ -374,7 +388,11 @@ These @tech{formlet}s are the main combinators for form input.
|
|||
[#:selected? selected? (any/c . -> . boolean?) (λ (x) #f)]
|
||||
[#:display display (any/c . -> . xexpr/c) (λ (x) x)])
|
||||
(formlet/c list?)]{
|
||||
This @tech{formlet} renders using an SELECT element with the attributes given with an OPTION for each element of the sequence. If @racket[multiple?] is @racket[#t], then multiple options may be selected. An element is selected if @racket[selected?] returns @racket[#t]. Elements are displayed with @racket[display].
|
||||
This @tech{formlet} renders using an SELECT element with the
|
||||
attributes given with an OPTION for each element of the sequence. If
|
||||
@racket[multiple?] is @racket[#t], then multiple options may be
|
||||
selected. An element is selected if @racket[selected?] returns
|
||||
@racket[#t]. Elements are displayed with @racket[display].
|
||||
}
|
||||
|
||||
@defproc[(select-input [l sequence?]
|
||||
|
@ -382,51 +400,62 @@ These @tech{formlet}s are the main combinators for form input.
|
|||
[#:selected? selected? (any/c . -> . boolean?) (λ (x) #f)]
|
||||
[#:display display (any/c . -> . xexpr/c) (λ (x) x)])
|
||||
(formlet/c any/c)]{
|
||||
This @tech{formlet} renders using an SELECT element with the attributes given with an OPTION for each element of the sequence. An element is selected if @racket[selected?] returns @racket[#t]. Elements are displayed with @racket[display].
|
||||
This @tech{formlet} renders using an SELECT element with the
|
||||
attributes given with an OPTION for each element of the sequence. An
|
||||
element is selected if @racket[selected?] returns
|
||||
@racket[#t]. Elements are displayed with @racket[display].
|
||||
}
|
||||
|
||||
@defproc[(required [f (formlet/c (or/c false/c binding?))])
|
||||
(formlet/c bytes?)]{
|
||||
Constructs a @tech{formlet} that extracts the @racket[binding:form-value] from the binding produced by @racket[f], or errors.
|
||||
Constructs a @tech{formlet} that extracts the
|
||||
@racket[binding:form-value] from the binding produced by @racket[f],
|
||||
or errors.
|
||||
}
|
||||
|
||||
@defproc[(default
|
||||
[def bytes?]
|
||||
[f (formlet/c (or/c false/c binding?))])
|
||||
(formlet/c bytes?)]{
|
||||
Constructs a @tech{formlet} that extracts the @racket[binding:form-value] from the binding produced by @racket[f], or returns @racket[def].
|
||||
Constructs a @tech{formlet} that extracts the
|
||||
@racket[binding:form-value] from the binding produced by @racket[f],
|
||||
or returns @racket[def].
|
||||
}
|
||||
|
||||
@defproc[(to-string [f (formlet/c bytes?)])
|
||||
(formlet/c string?)]{
|
||||
Converts @racket[f]'s output to a string. Equivalent to @racket[(cross (pure bytes->string/utf-8) f)].
|
||||
Converts @racket[f]'s output to a string. Equivalent to
|
||||
@racket[(cross (pure bytes->string/utf-8) f)].
|
||||
}
|
||||
|
||||
@defproc[(to-number [f (formlet/c string?)])
|
||||
(formlet/c number?)]{
|
||||
Converts @racket[f]'s output to a number. Equivalent to @racket[(cross (pure string->number) f)].
|
||||
Converts @racket[f]'s output to a number. Equivalent to @racket[(cross
|
||||
(pure string->number) f)].
|
||||
}
|
||||
|
||||
@defproc[(to-symbol [f (formlet/c string?)])
|
||||
(formlet/c symbol?)]{
|
||||
Converts @racket[f]'s output to a symbol. Equivalent to @racket[(cross (pure string->symbol) f)].
|
||||
Converts @racket[f]'s output to a symbol. Equivalent to
|
||||
@racket[(cross (pure string->symbol) f)].
|
||||
}
|
||||
|
||||
@defproc[(to-boolean [f (formlet/c bytes?)])
|
||||
(formlet/c boolean?)]{
|
||||
Converts @racket[f]'s output to a boolean, if it is equal to @racket[#"on"].
|
||||
Converts @racket[f]'s output to a boolean, if it is equal to
|
||||
@racket[#"on"].
|
||||
}
|
||||
|
||||
@defthing[input-string (formlet/c string?)]{
|
||||
Equivalent to @racket[(to-string (required (text-input)))].
|
||||
Equivalent to @racket[(to-string (required (text-input)))].
|
||||
}
|
||||
|
||||
@defthing[input-int (formlet/c integer?)]{
|
||||
Equivalent to @racket[(to-number input-string)].
|
||||
Equivalent to @racket[(to-number input-string)].
|
||||
}
|
||||
|
||||
@defthing[input-symbol (formlet/c symbol?)]{
|
||||
Equivalent to @racket[(to-symbol input-string)].
|
||||
Equivalent to @racket[(to-symbol input-string)].
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -446,16 +475,18 @@ A few utilities are provided for using @tech{formlet}s in Web applications.
|
|||
`(html (head (title "Form Entry"))
|
||||
(body ,form-xexpr)))])
|
||||
(values any/c ...)]{
|
||||
Uses @racket[send/suspend] and @racket[response/xexpr] to send @racket[f]'s rendering (wrapped in a FORM tag whose action is
|
||||
the continuation URL (wrapped again by @racket[wrapper])) to the client.
|
||||
When the form is submitted, the request is passed to the
|
||||
processing stage of @racket[f].
|
||||
Uses @racket[send/suspend] and @racket[response/xexpr] to send
|
||||
@racket[f]'s rendering (wrapped in a FORM tag whose action is the
|
||||
continuation URL (wrapped again by @racket[wrapper])) to the client.
|
||||
When the form is submitted, the request is passed to the processing
|
||||
stage of @racket[f].
|
||||
}
|
||||
|
||||
@defproc[(embed-formlet [embed/url ((request? . -> . any) . -> . string?)]
|
||||
[f (formlet/c any/c ...)])
|
||||
xexpr/c]{
|
||||
Like @racket[send/formlet], but for use with @racket[send/suspend/dispatch].
|
||||
Like @racket[send/formlet], but for use with
|
||||
@racket[send/suspend/dispatch].
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -278,8 +278,9 @@ transmission that the server @bold{will not catch}.}
|
|||
[domain (or/c false/c valid-domain?)]
|
||||
[path (or/c false/c string?)])]{
|
||||
|
||||
While server cookies are represented with @racket[cookie?]s, cookies that come from the client are represented
|
||||
with a @racket[client-cookie] structure.
|
||||
While server cookies are represented with @racket[cookie?]s, cookies
|
||||
that come from the client are represented with a
|
||||
@racket[client-cookie] structure.
|
||||
}
|
||||
|
||||
@defproc[(request-cookies [req request?])
|
||||
|
@ -423,15 +424,19 @@ An implementation of HTTP Digest Authentication.
|
|||
|
||||
@defproc[(password->digest-HA1 [lookup-password username*realm->password/c])
|
||||
username*realm->digest-HA1/c]{
|
||||
Uses @racket[lookup-password] to find the password, then computes the secret hash of it.
|
||||
Uses @racket[lookup-password] to find the password, then computes the
|
||||
secret hash of it.
|
||||
}
|
||||
|
||||
@defproc[(make-check-digest-credentials [lookup-HA1 username*realm->digest-HA1/c])
|
||||
(string? (listof (cons/c symbol? string?)) . -> . boolean?)]{
|
||||
Constructs a function that checks whether particular Digest credentials (the second argument of the returned function)
|
||||
are correct given the HTTP method provided as the first argument and the secret hash computed by @racket[lookup-HA1].
|
||||
Constructs a function that checks whether particular Digest credentials
|
||||
(the second argument of the returned function) are correct given the
|
||||
HTTP method provided as the first argument and the secret hash computed
|
||||
by @racket[lookup-HA1].
|
||||
|
||||
This is will result in an exception if the Digest credentials are missing portions.
|
||||
This is will result in an exception if the Digest credentials are
|
||||
missing portions.
|
||||
}
|
||||
|
||||
Example:
|
||||
|
|
|
@ -45,9 +45,9 @@ An example @racket['stateless] servlet module:
|
|||
(provide interface-version stuffer start)
|
||||
(define interface-version 'stateless)
|
||||
(define stuffer
|
||||
(stuffer-chain
|
||||
serialize-stuffer
|
||||
(md5-stuffer (build-path (find-system-path 'home-dir) ".urls"))))
|
||||
(stuffer-chain
|
||||
serialize-stuffer
|
||||
(md5-stuffer (build-path (find-system-path 'home-dir) ".urls"))))
|
||||
(define (start req)
|
||||
(response/xexpr
|
||||
`(html (body (h2 "Look ma, no state!")))))
|
||||
|
|
|
@ -21,10 +21,11 @@ of @racketmodname[web-server/dispatchers/dispatch-servlets].
|
|||
|
||||
@defproc[(make-make-servlet-namespace (#:to-be-copied-module-specs to-be-copied-module-specs (listof module-path?)))
|
||||
make-servlet-namespace/c]{
|
||||
This function creates a function that when called will construct a new @racket[namespace] that
|
||||
has all the modules from @racket[to-be-copied-module-specs] and @racket[additional-specs], as well
|
||||
as @racket[racket] and @racket[mred], provided they are already attached
|
||||
to the @racket[(current-namespace)] of the call-site.
|
||||
This function creates a function that when called will construct a new
|
||||
@racket[namespace] that has all the modules from
|
||||
@racket[to-be-copied-module-specs] and @racket[additional-specs], as
|
||||
well as @racket[racket] and @racket[mred], provided they are already
|
||||
attached to the @racket[(current-namespace)] of the call-site.
|
||||
|
||||
Example:
|
||||
@racketblock[
|
||||
|
@ -37,14 +38,17 @@ Example:
|
|||
|
||||
@section{Why this is useful}
|
||||
|
||||
A different namespace is needed for each servlet, so that if servlet A and servlet B both use
|
||||
a stateful module C, they will be isolated from one another. We see the @web-server as
|
||||
an operating system for servlets, so we inherit the isolation requirement on operating systems.
|
||||
A different namespace is needed for each servlet, so that if servlet A
|
||||
and servlet B both use a stateful module C, they will be isolated from
|
||||
one another. We see the @web-server as an operating system for servlets,
|
||||
so we inherit the isolation requirement on operating systems.
|
||||
|
||||
However, there are some modules which must be shared. If they were not, then structures cannot
|
||||
be passed from the @web-server to the servlets, because Racket's structures are generative.
|
||||
However, there are some modules which must be shared. If they were not,
|
||||
then structures cannot be passed from the @web-server to the servlets,
|
||||
because Racket's structures are generative.
|
||||
|
||||
Since, on occasion, a user will actually wanted servlets A and B to interact through module C.
|
||||
A custom @racket[make-servlet-namespace] can be created, through this procedure, that attaches
|
||||
module C to all servlet namespaces. Through other means (see @secref["dispatchers"]) different sets
|
||||
of servlets can share different sets of modules.
|
||||
Since, on occasion, a user will actually wanted servlets A and B to
|
||||
interact through module C. A custom @racket[make-servlet-namespace] can
|
||||
be created, through this procedure, that attaches module C to all
|
||||
servlet namespaces. Through other means (see @secref["dispatchers"])
|
||||
different sets of servlets can share different sets of modules.
|
||||
|
|
|
@ -9,12 +9,17 @@
|
|||
|
||||
@defmodule[web-server/lang/native]{
|
||||
|
||||
It is sometimes inconvenient to use @racket[serial->native] and @racket[native->serial] throughout your program.
|
||||
This module provides a macro for creating wrappers.
|
||||
It is sometimes inconvenient to use @racket[serial->native] and
|
||||
@racket[native->serial] throughout your program. This module provides a
|
||||
macro for creating wrappers.
|
||||
|
||||
@defform[#:literals (ho) (define-native (native arg-spec ...) original) #:contracts ([arg-spec ho] [arg-spec _])]{
|
||||
Builds an interface around @racket[original] named @racket[native] such that calls to @racket[native] are wrapped in @racket[serial->native]
|
||||
and all arguments marked with @racket[ho] in @racket[arg-spec] are assumed to procedures and are wrapped in @racket[native->serial].
|
||||
@defform[#:literals (ho)
|
||||
(define-native (native arg-spec ...) original)
|
||||
#:contracts ([arg-spec ho] [arg-spec _])]{
|
||||
Builds an interface around @racket[original] named @racket[native] such
|
||||
that calls to @racket[native] are wrapped in @racket[serial->native]
|
||||
and all arguments marked with @racket[ho] in @racket[arg-spec] are
|
||||
assumed to procedures and are wrapped in @racket[native->serial].
|
||||
|
||||
For example,
|
||||
@racketblock[
|
||||
|
|
|
@ -39,33 +39,59 @@ A simple example:
|
|||
"You clicked!"))])
|
||||
"Click me")))))]
|
||||
|
||||
Similarly, many Web applications make use almost exclusively of functions that are arguments to @racket[embed/url] and immediately invoke @racket[send/suspend/dispatch].
|
||||
Similarly, many Web applications make use almost exclusively of
|
||||
functions that are arguments to @racket[embed/url] and immediately
|
||||
invoke @racket[send/suspend/dispatch].
|
||||
|
||||
@deftogether[[@defform[(lambda/page formals e ...)]
|
||||
@defform[(define/page (id . formals) e ...)]]]{
|
||||
The @racket[lambda/page] and @racket[define/page] automate this by expanding to functions that accept a request as the first argument (followed by any arguments specified in @racket[formals]) and immediately wrap their body in @racket[page]. This functions also cooperate with @racket[get-binding] by binding the request to the @racket[current-request] parameter.
|
||||
The @racket[lambda/page] and @racket[define/page] automate this by
|
||||
expanding to functions that accept a request as the first argument
|
||||
(followed by any arguments specified in @racket[formals]) and
|
||||
immediately wrap their body in @racket[page]. This functions also
|
||||
cooperate with @racket[get-binding] by binding the request to the
|
||||
@racket[current-request] parameter.
|
||||
}
|
||||
|
||||
The binding interface of @racketmodname[web-server/http] is powerful, but subtle to use conveniently due to its protection against hostile clients.
|
||||
The binding interface of @racketmodname[web-server/http] is powerful,
|
||||
but subtle to use conveniently due to its protection against hostile
|
||||
clients.
|
||||
|
||||
@deftogether[[
|
||||
@defparam[current-request req request?]
|
||||
@defthing[binding-id/c contract?]
|
||||
@defthing[binding-format/c contract?]
|
||||
@defproc[(get-binding [id binding-id/c] [req request? (current-request)] [#:format format binding-format/c 'string])
|
||||
@defproc[(get-binding [id binding-id/c]
|
||||
[req request? (current-request)]
|
||||
[#:format format binding-format/c 'string])
|
||||
(or/c false/c string? bytes? binding?)]
|
||||
@defproc[(get-bindings [id binding-id/c] [req request? (current-request)] [#:format format binding-format/c 'string])
|
||||
@defproc[(get-bindings [id binding-id/c]
|
||||
[req request? (current-request)]
|
||||
[#:format format binding-format/c 'string])
|
||||
(listof (or/c string? bytes? binding?))]
|
||||
]]{
|
||||
|
||||
The @racket[get-binding](s) interface attempts to resolve this by providing a powerful interface with convenient defaults.
|
||||
The @racket[get-binding](s) interface attempts to resolve this by
|
||||
providing a powerful interface with convenient defaults.
|
||||
|
||||
@racket[get-binding] extracts the first binding of a form input from a request, while @racket[get-bindings] extracts them all.
|
||||
@racket[get-binding] extracts the first binding of a form input from a
|
||||
request, while @racket[get-bindings] extracts them all.
|
||||
|
||||
They accept a form identifier (@racket[id]) as either a byte string, a string, or a symbol. In each case, the user input is compared in a case-sensitive way with the form input.
|
||||
They accept a form identifier (@racket[id]) as either a byte string, a
|
||||
string, or a symbol. In each case, the user input is compared in a
|
||||
case-sensitive way with the form input.
|
||||
|
||||
They accept an optional request argument (@racket[req]) that defaults to the value of the @racket[current-request] parameter used by @racket[lambda/page] and @racket[define/page].
|
||||
They accept an optional request argument (@racket[req]) that defaults
|
||||
to the value of the @racket[current-request] parameter used by
|
||||
@racket[lambda/page] and @racket[define/page].
|
||||
|
||||
Finally, they accept an optional keyword argument (@racket[format]) that specifies the desired return format. The default, @racket['string], produces a UTF-8 string (or @racket[#f] if the byte string cannot be converted to UTF-8.) The @racket['bytes] format always produces the raw byte string. The @racket['file] format produces the file upload content (or @racket[#f] if the form input was not an uploaded file.) The @racket['binding] format produces the binding object.
|
||||
Finally, they accept an optional keyword argument (@racket[format])
|
||||
that specifies the desired return format. The default,
|
||||
@racket['string], produces a UTF-8 string (or @racket[#f] if the byte
|
||||
string cannot be converted to UTF-8.) The @racket['bytes] format
|
||||
always produces the raw byte string. The @racket['file] format
|
||||
produces the file upload content (or @racket[#f] if the form input was
|
||||
not an uploaded file.) The @racket['binding] format produces the
|
||||
binding object.
|
||||
|
||||
}
|
||||
|
|
|
@ -8,70 +8,88 @@
|
|||
|
||||
@defmodule[web-server/configuration/responders]{
|
||||
|
||||
This module provides some functions that help constructing HTTP responders.
|
||||
These functions are used by the default dispatcher constructor (see @secref["web-server-unit"]) to
|
||||
turn the paths given in the @racket[configuration-table] into responders for the associated circumstance.
|
||||
This module provides some functions that help constructing HTTP
|
||||
responders. These functions are used by the default dispatcher
|
||||
constructor (see @secref["web-server-unit"]) to turn the paths given in
|
||||
the @racket[configuration-table] into responders for the associated
|
||||
circumstance.
|
||||
|
||||
@defproc[(file-response (http-code natural-number/c) (short-version string?) (text-file string?) (header header?) ...)
|
||||
@defproc[(file-response [http-code natural-number/c]
|
||||
[short-version string?]
|
||||
[text-file string?]
|
||||
[header header?] ...)
|
||||
response?]{
|
||||
Generates a @racket[response?] with the given @racket[http-code] and @racket[short-version]
|
||||
as the corresponding fields; with the content of the @racket[text-file] as the body; and, with
|
||||
the @racket[header]s as, you guessed it, headers.
|
||||
Generates a @racket[response?] with the given @racket[http-code] and
|
||||
@racket[short-version] as the corresponding fields; with the content of
|
||||
the @racket[text-file] as the body; and, with the @racket[header]s as,
|
||||
you guessed it, headers.
|
||||
|
||||
This does not cause redirects to a well-known URL, such as @filepath{conf/not-found.html}, but rather use the contents
|
||||
of @filepath{not-found.html} (for example) as its contents. Therefore, any relative URLs in @racket[text-file] are relative
|
||||
to whatever URL @racket[file-response] is used to respond @emph{to}. Thus, you should probably use absolute URLs in these files.
|
||||
This does not cause redirects to a well-known URL, such as
|
||||
@filepath{conf/not-found.html}, but rather use the contents of
|
||||
@filepath{not-found.html} (for example) as its contents. Therefore, any
|
||||
relative URLs in @racket[text-file] are relative to whatever URL
|
||||
@racket[file-response] is used to respond @emph{to}. Thus, you should
|
||||
probably use absolute URLs in these files.
|
||||
}
|
||||
|
||||
@defproc[(servlet-loading-responder (url url?) (exn exn?))
|
||||
@defproc[(servlet-loading-responder [url url?] [exn exn?])
|
||||
response?]{
|
||||
Gives @racket[exn] to the @racket[current-error-handler] and response with a stack trace and a "Servlet didn't load" message.
|
||||
Gives @racket[exn] to the @racket[current-error-handler] and response
|
||||
with a stack trace and a "Servlet didn't load" message.
|
||||
}
|
||||
|
||||
@defproc[(gen-servlet-not-found (file path-string?))
|
||||
@defproc[(gen-servlet-not-found [file path-string?])
|
||||
((url url?) . -> . response?)]{
|
||||
Returns a function that generates a standard "Servlet not found." error with content from @racket[file].
|
||||
Returns a function that generates a standard "Servlet not found." error
|
||||
with content from @racket[file].
|
||||
}
|
||||
|
||||
@defproc[(servlet-error-responder (url url?) (exn exn?))
|
||||
@defproc[(servlet-error-responder [url url?] [exn exn?])
|
||||
response?]{
|
||||
Gives @racket[exn] to the @racket[current-error-handler] and response with a stack trace and a "Servlet error" message.
|
||||
Gives @racket[exn] to the @racket[current-error-handler] and response
|
||||
with a stack trace and a "Servlet error" message.
|
||||
}
|
||||
|
||||
@defproc[(gen-servlet-responder (file path-string?))
|
||||
@defproc[(gen-servlet-responder [file path-string?])
|
||||
((url url?) (exn any/c) . -> . response?)]{
|
||||
Prints the @racket[exn] to standard output and responds with a "Servlet error." message with content from @racket[file].
|
||||
Prints the @racket[exn] to standard output and responds with a "Servlet
|
||||
error." message with content from @racket[file].
|
||||
}
|
||||
|
||||
@defproc[(gen-servlets-refreshed (file path-string?))
|
||||
@defproc[(gen-servlets-refreshed [file path-string?])
|
||||
(-> response?)]{
|
||||
Returns a function that generates a standard "Servlet cache refreshed." message with content from @racket[file].
|
||||
Returns a function that generates a standard "Servlet cache refreshed."
|
||||
message with content from @racket[file].
|
||||
}
|
||||
|
||||
@defproc[(gen-passwords-refreshed (file path-string?))
|
||||
@defproc[(gen-passwords-refreshed [file path-string?])
|
||||
(-> response?)]{
|
||||
Returns a function that generates a standard "Passwords refreshed." message with content from @racket[file].
|
||||
Returns a function that generates a standard "Passwords refreshed."
|
||||
message with content from @racket[file].
|
||||
}
|
||||
|
||||
@defproc[(gen-authentication-responder (file path-string?))
|
||||
@defproc[(gen-authentication-responder [file path-string?])
|
||||
((url url?) (header header?) . -> . response?)]{
|
||||
Returns a function that generates an authentication failure error with content from @racket[file] and
|
||||
@racket[header] as the HTTP header.
|
||||
Returns a function that generates an authentication failure error with
|
||||
content from @racket[file] and @racket[header] as the HTTP header.
|
||||
}
|
||||
|
||||
@defproc[(gen-protocol-responder (file path-string?))
|
||||
@defproc[(gen-protocol-responder [file path-string?])
|
||||
((url url?) . -> . response?)]{
|
||||
Returns a function that generates a "Malformed request" error with content from @racket[file].
|
||||
Returns a function that generates a "Malformed request" error with
|
||||
content from @racket[file].
|
||||
}
|
||||
|
||||
@defproc[(gen-file-not-found-responder (file path-string?))
|
||||
@defproc[(gen-file-not-found-responder [file path-string?])
|
||||
((req request?) . -> . response?)]{
|
||||
Returns a function that generates a standard "File not found" error with content from @racket[file].
|
||||
Returns a function that generates a standard "File not found" error
|
||||
with content from @racket[file].
|
||||
}
|
||||
|
||||
@defproc[(gen-collect-garbage-responder (file path-string?))
|
||||
@defproc[(gen-collect-garbage-responder [file path-string?])
|
||||
(-> response?)]{
|
||||
Returns a function that generates a standard "Garbage collection run" message with content from @racket[file].
|
||||
Returns a function that generates a standard "Garbage collection run"
|
||||
message with content from @racket[file].
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,7 +23,10 @@ and increasing the size of the serialization. This module provides support for t
|
|||
|
||||
@defproc[(soft-state-ref [ss soft-state?])
|
||||
any/c]{
|
||||
Extracts the value associated with @racket[ss]. If the value is not available (perhaps because of garbage collection, deserialization in an uninitialized process, etc), then the thunk associated with @racket[ss] is invoked and the value is cached.
|
||||
Extracts the value associated with @racket[ss]. If the value is not
|
||||
available (perhaps because of garbage collection, deserialization in an
|
||||
uninitialized process, etc), then the thunk associated with @racket[ss]
|
||||
is invoked and the value is cached.
|
||||
}
|
||||
|
||||
@defform[(soft-state expr ...)]{
|
||||
|
|
|
@ -6,10 +6,11 @@
|
|||
|
||||
@title[#:tag "considerations"]{Usage Considerations}
|
||||
|
||||
A stateless servlet has the following process performed on it automatically:
|
||||
A stateless servlet has the following process performed on it
|
||||
automatically:
|
||||
@itemize[
|
||||
@item{All uses of @racket[letrec] are removed and replaced with equivalent uses of
|
||||
@racket[let] and imperative features.}
|
||||
@item{All uses of @racket[letrec] are removed and replaced with
|
||||
equivalent uses of @racket[let] and imperative features.}
|
||||
@item{The program is converted into @link["http://en.wikipedia.org/wiki/Administrative_normal_form"]{ANF} (Administrative Normal Form),
|
||||
making all continuations explicit.}
|
||||
@item{All continuations and continuations marks are recorded in the
|
||||
|
@ -22,41 +23,47 @@ A stateless servlet has the following process performed on it automatically:
|
|||
@racket[lambda].}
|
||||
]
|
||||
|
||||
This process allows the continuations captured by your servlet to be serialized.
|
||||
This means they may be stored on the client's browser or the server's disk.
|
||||
This process allows the continuations captured by your servlet to be
|
||||
serialized. This means they may be stored on the client's browser or
|
||||
the server's disk.
|
||||
|
||||
This means your servlet has no cost to the server other than execution. This is
|
||||
very attractive if you've used Racket servlets and had memory problems.
|
||||
This means your servlet has no cost to the server other than
|
||||
execution. This is very attractive if you've used Racket servlets and
|
||||
had memory problems.
|
||||
|
||||
This means your server can restart in the middle of a long running Web interaction
|
||||
without the URLs that have been shared with the client expiring. This is
|
||||
very attractive if you've used Racket servlets and had session timeout problems.
|
||||
This means your server can restart in the middle of a long running Web
|
||||
interaction without the URLs that have been shared with the client
|
||||
expiring. This is very attractive if you've used Racket servlets and
|
||||
had session timeout problems.
|
||||
|
||||
This process is defined on all of Racket and occurs after macro-expansion,
|
||||
so you are free to use all interesting features of Racket. However, there
|
||||
are some considerations you must make.
|
||||
This process is defined on all of Racket and occurs after
|
||||
macro-expansion, so you are free to use all interesting features of
|
||||
Racket. However, there are some considerations you must make.
|
||||
|
||||
First, this process drastically changes the structure of your program. It
|
||||
will create an immense number of lambdas and structures your program
|
||||
did not normally contain. The performance implication of this has not been
|
||||
studied with Racket.
|
||||
First, this process drastically changes the structure of your program.
|
||||
It will create an immense number of lambdas and structures your program
|
||||
did not normally contain. The performance implication of this has not
|
||||
been studied with Racket.
|
||||
|
||||
Second, the defunctionalization process is sensitive to the syntactic structure
|
||||
of your program. Therefore, if you change your program in a trivial way, for example,
|
||||
changing a constant, then all serialized continuations will be obsolete and will
|
||||
error when deserialization is attempted. This is a feature, not a bug! It is a small
|
||||
price to pay for protection from the sorts of errors that would occur if your program
|
||||
Second, the defunctionalization process is sensitive to the syntactic
|
||||
structure of your program. Therefore, if you change your program in a
|
||||
trivial way, for example, changing a constant, then all serialized
|
||||
continuations will be obsolete and will error when deserialization is
|
||||
attempted. This is a feature, not a bug! It is a small price to pay for
|
||||
protection from the sorts of errors that would occur if your program
|
||||
were changed in a meaningful way.
|
||||
|
||||
Third, the values in the lexical scope of your continuations must be serializable
|
||||
for the continuations itself to be serializable. This means that you must use
|
||||
@racket[define-serializable-struct] rather than @racket[define-struct], and take
|
||||
care to use modules that do the same. Similarly, you may not use @racket[parameterize],
|
||||
because parameterizations are not serializable.
|
||||
Third, the values in the lexical scope of your continuations must be
|
||||
serializable for the continuations itself to be serializable. This means
|
||||
that you must use @racket[define-serializable-struct] rather than
|
||||
@racket[define-struct], and take care to use modules that do the same.
|
||||
Similarly, you may not use @racket[parameterize], because
|
||||
parameterizations are not serializable.
|
||||
|
||||
Fourth, and related, this process only runs on your code, not on the code you
|
||||
@racket[require]. Thus, your continuations---to be serializable---must not
|
||||
be in the context of another module. For example, the following will fail with an @as-index{"unsafe context"}
|
||||
Fourth, and related, this process only runs on your code, not on the
|
||||
code you @racket[require]. Thus, your continuations---to be
|
||||
serializable---must not be in the context of another module. For
|
||||
example, the following will fail with an @as-index{"unsafe context"}
|
||||
exception:
|
||||
|
||||
@racketblock[
|
||||
|
|
|
@ -52,8 +52,9 @@ You can supply your own (built with these functions) when you write a stateless
|
|||
@defproc[(stuffer-compose [g (stuffer/c any/c any/c)]
|
||||
[f (stuffer/c any/c any/c)])
|
||||
(stuffer/c any/c any/c)]{
|
||||
Composes @racket[f] and @racket[g], i.e., applies @racket[f] then @racket[g] for @racket[in]
|
||||
and @racket[g] then @racket[f] for @racket[out].
|
||||
Composes @racket[f] and @racket[g], i.e., applies @racket[f] then
|
||||
@racket[g] for @racket[in] and @racket[g] then @racket[f] for
|
||||
@racket[out].
|
||||
}
|
||||
|
||||
@defproc[(stuffer-sequence [f (stuffer/c any/c any/c)]
|
||||
|
@ -65,9 +66,10 @@ You can supply your own (built with these functions) when you write a stateless
|
|||
@defproc[(stuffer-if [c (bytes? . -> . boolean?)]
|
||||
[f (stuffer/c bytes? bytes?)])
|
||||
(stuffer/c bytes? bytes?)]{
|
||||
Creates a @tech{stuffer} that stuffs with @racket[f] if @racket[c] is true on the input
|
||||
to @racket[in]. Similarly, applies @racket[f] during @racket[out] if it was applied during
|
||||
@racket[in] (which is recorded by prepending a byte.)
|
||||
Creates a @tech{stuffer} that stuffs with @racket[f] if @racket[c] is
|
||||
true on the input to @racket[in]. Similarly, applies @racket[f] during
|
||||
@racket[out] if it was applied during @racket[in] (which is recorded by
|
||||
prepending a byte.)
|
||||
}
|
||||
|
||||
@defproc[(stuffer-chain [x (or/c stuffer? (bytes? . -> . boolean?))]
|
||||
|
@ -85,7 +87,8 @@ You can supply your own (built with these functions) when you write a stateless
|
|||
@defmodule[web-server/stuffers/serialize]{
|
||||
|
||||
@defthing[serialize-stuffer (stuffer/c serializable? bytes?)]{
|
||||
A @tech{stuffer} that uses @racket[serialize] and @racket[write/bytes] and @racket[deserialize] and @racket[read/bytes].
|
||||
A @tech{stuffer} that uses @racket[serialize] and @racket[write/bytes]
|
||||
and @racket[deserialize] and @racket[read/bytes].
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -111,14 +114,16 @@ You can supply your own (built with these functions) when you write a stateless
|
|||
@defthing[gzip-stuffer (stuffer/c bytes? bytes?)]{
|
||||
A @tech{stuffer} that uses @racket[gzip/bytes] and @racket[gunzip/bytes].
|
||||
|
||||
@warning{You should compose this with @racket[base64-stuffer] to get URL-safe bytes.}
|
||||
@warning{You should compose this with @racket[base64-stuffer] to get
|
||||
URL-safe bytes.}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@section{Key/Value Storage}
|
||||
|
||||
The @racketmodname[web-server/stuffers/hash] @tech{stuffers} rely on a key/value store.
|
||||
The @racketmodname[web-server/stuffers/hash] @tech{stuffers} rely on a
|
||||
key/value store.
|
||||
|
||||
@defmodule[web-server/stuffers/store]{
|
||||
|
||||
|
@ -155,8 +160,10 @@ The @racketmodname[web-server/stuffers/hash] @tech{stuffers} rely on a key/value
|
|||
@defproc[(hash-stuffer [H hash-fun/c]
|
||||
[store store?])
|
||||
(stuffer/c bytes? bytes?)]{
|
||||
A content-addressed storage @tech{stuffer} that stores input bytes, @racket[input], in @racket[store] with the key @racket[(H input)]
|
||||
and returns the key. Similarly, on @racket[out] the original bytes are looked up.
|
||||
A content-addressed storage @tech{stuffer} that stores input bytes,
|
||||
@racket[input], in @racket[store] with the key @racket[(H input)] and
|
||||
returns the key. Similarly, on @racket[out] the original bytes are
|
||||
looked up.
|
||||
}
|
||||
|
||||
@defproc[(md5-stuffer [root path-string?])
|
||||
|
@ -172,24 +179,32 @@ The @racketmodname[web-server/stuffers/hash] @tech{stuffers} rely on a key/value
|
|||
|
||||
@defproc[(HMAC-SHA1 [kb bytes?] [db bytes?])
|
||||
bytes?]{
|
||||
Performs a HMAC-SHA1 calculation on @racket[db] using @racket[kb] as the key. The result is guaranteed to be 20 bytes.
|
||||
(You could curry this to use it with @racket[hash-stuffer], but there is little value in doing so over @racket[md5].)
|
||||
|
||||
Performs a HMAC-SHA1 calculation on @racket[db] using @racket[kb] as
|
||||
the key. The result is guaranteed to be 20 bytes. (You could curry
|
||||
this to use it with @racket[hash-stuffer], but there is little value
|
||||
in doing so over @racket[md5].)
|
||||
}
|
||||
|
||||
@defproc[(HMAC-SHA1-stuffer [kb bytes?])
|
||||
(stuffer/c bytes? bytes?)]{
|
||||
A @tech{stuffer} that signs input using @racket[HMAC-SHA1] with @racket[kb] as the key. The result of the @tech{stuffer} is
|
||||
the hash prepended to the input data. When the @tech{stuffer} is run in reverse, it checks if the first 20 bytes are the correct
|
||||
has for the rest of the data.
|
||||
A @tech{stuffer} that signs input using @racket[HMAC-SHA1] with
|
||||
@racket[kb] as the key. The result of the @tech{stuffer} is the hash
|
||||
prepended to the input data. When the @tech{stuffer} is run in
|
||||
reverse, it checks if the first 20 bytes are the correct has for the
|
||||
rest of the data.
|
||||
|
||||
@warning{You should compose this with @racket[base64-stuffer] to get URL-safe bytes.}
|
||||
@warning{You should compose this with @racket[base64-stuffer] to get
|
||||
URL-safe bytes.}
|
||||
|
||||
@warning{Without explicit provision, it is possible for users to modify the continuations they are sent through the other @tech{stuffers}.
|
||||
This @tech{stuffer} allows the servlet to certify that stuffed data was truly generated by the servlet. Therefore, you @bold{should} use this
|
||||
if you are not using the @racket[hash-stuffer]s.}
|
||||
@warning{Without explicit provision, it is possible for users to
|
||||
modify the continuations they are sent through the other
|
||||
@tech{stuffers}. This @tech{stuffer} allows the servlet to certify
|
||||
that stuffed data was truly generated by the servlet. Therefore, you
|
||||
@bold{should} use this if you are not using the
|
||||
@racket[hash-stuffer]s.}
|
||||
|
||||
@warning{This @tech{stuffer} does @bold{not} encrypt the data in anyway, so users can still observe the stuffed values.}
|
||||
@warning{This @tech{stuffer} does @bold{not} encrypt the data in
|
||||
anyway, so users can still observe the stuffed values.}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -200,14 +215,17 @@ The @racketmodname[web-server/stuffers/hash] @tech{stuffers} rely on a key/value
|
|||
|
||||
@defproc[(is-url-too-big? [v bytes?])
|
||||
boolean?]{
|
||||
Determines if stuffing @racket[v] into the current servlet's URL would result in a URL that is too big for Internet Explorer.
|
||||
(@link["http://www.boutell.com/newfaq/misc/urllength.html"]{IE only supports URLs up to 2048 characters.})
|
||||
Determines if stuffing @racket[v] into the current servlet's URL would
|
||||
result in a URL that is too big for Internet Explorer.
|
||||
(@link["http://www.boutell.com/newfaq/misc/urllength.html"]{IE only
|
||||
supports URLs up to 2048 characters.})
|
||||
}
|
||||
|
||||
@defproc[(make-default-stuffer [root path-string?])
|
||||
(stuffer/c serializable? bytes?)]{
|
||||
Constructs a @tech{stuffer} that serializes, then if the URL is too big, compresses (and base64-encodes), if the URL is still too big
|
||||
then it stores it in an MD5-indexed database rooted at @racket[root].
|
||||
Constructs a @tech{stuffer} that serializes, then if the URL is too
|
||||
big, compresses (and base64-encodes), if the URL is still too big then
|
||||
it stores it in an MD5-indexed database rooted at @racket[root].
|
||||
|
||||
Equivalent to:
|
||||
@racketblock[
|
||||
|
|
|
@ -293,7 +293,7 @@ the template to be unescaped, then create a @racket[cdata] structure:
|
|||
Expands into
|
||||
@racketblock[
|
||||
(for/list ([x xs])
|
||||
(begin/text e ...))
|
||||
(begin/text e ...))
|
||||
]
|
||||
|
||||
Template Example:
|
||||
|
|
|
@ -36,7 +36,10 @@ This function accepts a servlet function and provides a function that accepts a
|
|||
]
|
||||
}
|
||||
|
||||
This facility is designed to be used in concert with a technique of extracting continuation URLs and relevant values; @racketmodname[xml/path] is one way to do this. Here is an extended example that tests an Add-Two-Numbers.com:
|
||||
This facility is designed to be used in concert with a technique of
|
||||
extracting continuation URLs and relevant values;
|
||||
@racketmodname[xml/path] is one way to do this. Here is an extended
|
||||
example that tests an Add-Two-Numbers.com:
|
||||
@(require (for-label xml/path
|
||||
rackunit
|
||||
racket/list
|
||||
|
|
|
@ -95,17 +95,22 @@ represented as an X-expression in Racket, by using
|
|||
|
||||
@racketblock[
|
||||
(define xexpr/c
|
||||
(flat-rec-contract
|
||||
xexpr
|
||||
(or/c string?
|
||||
(or/c (cons/c symbol? (listof xexpr))
|
||||
(cons/c symbol?
|
||||
(cons/c (listof (list/c symbol? string?))
|
||||
(listof xexpr)))))))]
|
||||
(flat-rec-contract
|
||||
xexpr
|
||||
(or/c string?
|
||||
(or/c (cons/c symbol? (listof xexpr))
|
||||
(cons/c symbol?
|
||||
(cons/c (listof (list/c symbol? string?))
|
||||
(listof xexpr)))))))]
|
||||
|
||||
For example:
|
||||
|
||||
The HTML @tt{hello} is represented as @racket["hello"]. Strings are automatically escaped when output. This guarantees valid HTML. Therefore, the value @racket["<b>Unfinished tag"] is rendered as @tt{<b>Unfinished tag} not @tt{<b>Unfinished tag}. Similarly, @racket["<i>Finished tag</i>"] is rendered as @tt{<i>Finished tag</i>} not @tt{<i>Finished tag</i>}.
|
||||
The HTML @tt{hello} is represented as @racket["hello"]. Strings are
|
||||
automatically escaped when output. This guarantees valid HTML.
|
||||
Therefore, the value @racket["<b>Unfinished tag"] is rendered as
|
||||
@tt{<b>Unfinished tag} not @tt{<b>Unfinished tag}. Similarly,
|
||||
@racket["<i>Finished tag</i>"] is rendered as
|
||||
@tt{<i>Finished tag</i>} not @tt{<i>Finished tag</i>}.
|
||||
|
||||
@tt{<p>This is an example</p>} is
|
||||
|
||||
|
|
|
@ -51,19 +51,19 @@ transformations of the program into continuation or store passing style.
|
|||
web-server/insta
|
||||
|
||||
(define (start initial-request)
|
||||
(define counter1 (make-counter))
|
||||
(define counter2 (make-counter))
|
||||
(define include1 (include-counter counter1))
|
||||
(define include2 (include-counter counter2))
|
||||
(send/suspend/dispatch
|
||||
(lambda (embed/url)
|
||||
(response/xexpr
|
||||
`(html
|
||||
(body (h2 "Double Counters")
|
||||
(div (h3 "First")
|
||||
,(include1 embed/url))
|
||||
(div (h3 "Second")
|
||||
,(include2 embed/url))))))))
|
||||
(define counter1 (make-counter))
|
||||
(define counter2 (make-counter))
|
||||
(define include1 (include-counter counter1))
|
||||
(define include2 (include-counter counter2))
|
||||
(send/suspend/dispatch
|
||||
(lambda (embed/url)
|
||||
(response/xexpr
|
||||
`(html
|
||||
(body (h2 "Double Counters")
|
||||
(div (h3 "First")
|
||||
,(include1 embed/url))
|
||||
(div (h3 "Second")
|
||||
,(include2 embed/url))))))))
|
||||
|
||||
(define (make-counter)
|
||||
(make-web-cell 0))
|
||||
|
|
|
@ -212,6 +212,7 @@ functions of interest for the servlet developer.
|
|||
returns the instance id, continuation id, and nonce.
|
||||
}
|
||||
|
||||
@defthing[servlet-prompt continuation-prompt-tag?]{The tag used for Web interaction continuation capture.}
|
||||
@defthing[servlet-prompt continuation-prompt-tag?]{
|
||||
The tag used for Web interaction continuation capture.}
|
||||
|
||||
}
|
||||
|
|
|
@ -47,7 +47,8 @@ Represents a location in an input stream.}
|
|||
@defstruct[source ([start location/c]
|
||||
[stop location/c])]{
|
||||
|
||||
Represents a source location. Other structure types extend @racket[source].
|
||||
Represents a source location. Other structure types extend
|
||||
@racket[source].
|
||||
|
||||
When XML is generated from an input stream by @racket[read-xml],
|
||||
locations are represented by @racket[location] instances. When XML
|
||||
|
@ -174,7 +175,8 @@ and a @racket[_misc] is an instance of the @racket[comment] or
|
|||
@racket[p-i] structure types.}
|
||||
|
||||
@defthing[xexpr/c contract?]{
|
||||
A contract that is like @racket[xexpr?] except produces a better error message when the value is not an @tech{X-expression}.
|
||||
A contract that is like @racket[xexpr?] except produces a better error
|
||||
message when the value is not an @tech{X-expression}.
|
||||
}
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue
Block a user