svn: r13056

This commit is contained in:
Matthias Felleisen 2009-01-09 23:45:05 +00:00
parent 38ef7d3c41
commit a6f08c7399

View File

@ -915,6 +915,9 @@ Understanding the server's event handling functions demands three
@defproc[(world=? [u world?][v world?]) boolean?]{ @defproc[(world=? [u world?][v world?]) boolean?]{
compares two @emph{world}s for equality.} compares two @emph{world}s for equality.}
defproc[(world-name [w world?]) symbol?]{
extracts the name from a @emph{world} structure.}
@defthing[world1 world?]{a world for testing your programs} @defthing[world1 world?]{a world for testing your programs}
@defthing[world2 world?]{another world for testing your programs} @defthing[world2 world?]{another world for testing your programs}
@defthing[world3 world?]{and a third one} @defthing[world3 world?]{and a third one}
@ -941,14 +944,14 @@ structures:
@item{Each event handler produces a @emph{bundle}, which is a structure @item{Each event handler produces a @emph{bundle}, which is a structure
that contains the @tech{server}'s state and a list of mails to other that contains the @tech{server}'s state and a list of mails to other
worlds. Again, the teachpack provides only the predicate and a constructor: worlds. Again, the teachpack provides only the predicate and a constructor:
@defproc[(bundle? [x any/c]) boolean?]{ @defproc[(bundle? [x any/c]) boolean?]{
determines whether @scheme[x] is a @emph{bundle}.} determines whether @scheme[x] is a @emph{bundle}.}
@defproc[(make-bundle [state any/c] [mails (listof mail?)]) bundle?]{ @defproc[(make-bundle [listof world?] [state any/c] [mails (listof mail?)]) bundle?]{
creates a @emph{bundle} from a piece of data that represents a server creates a @emph{bundle} from a list of worlds, a piece of data that represents a server
state and a list of mails.} state, and a list of mails.}
} }
] ]
@ -1001,7 +1004,6 @@ A @scheme[universe] expression starts a server. Visually it opens
especially useful during the integration of the various pieces of a especially useful during the integration of the various pieces of a
distributed program. distributed program.
Now it is possible to explain the clauses in a @scheme[universe] server Now it is possible to explain the clauses in a @scheme[universe] server
description. Two of them are mandatory: description. Two of them are mandatory:
@ -1010,22 +1012,26 @@ description. Two of them are mandatory:
@item{ @item{
@defform[(on-new new-expr) @defform[(on-new new-expr)
#:contracts #:contracts
([new-expr (-> (unsyntax @tech{UniverseState}) world? ([new-expr (-> [listof world?] (unsyntax @tech{UniverseState}) world? bundle?)])]{
(cons (unsyntax @tech{UniverseState}) [listof mail?]))])]{
tell DrScheme to call the function @scheme[new-expr] every time another world joins the tell DrScheme to call the function @scheme[new-expr] every time another world joins the
universe.}} universe. The event handler is called on the current list of worlds and the
joining world.
}}
@item{ @item{
@defform[(on-msg msg-expr) @defform[(on-msg msg-expr)
#:contracts #:contracts
([msg-expr (-> (unsyntax @tech{UniverseState}) world? sexp? ([msg-expr (-> [listof world?] (unsyntax @tech{UniverseState}) world? sexp? bundle?)])]{
(cons (unsyntax @tech{UniverseState}) [listof mail?]))])]{
tell DrScheme to apply @scheme[msg-expr] to the current state of the universe, the world tell DrScheme to apply @scheme[msg-expr] to the list of currently
that sent the message, and the message itself. The handler must produce a state of the participating worlds, the current state of the universe, the world
universe and a list of mails.} that sent the message, and the message itself.}
} }
] ]
All event handlers produce a @emph{bundle}. The list of worlds in this
@emph{bundle} becomes the server's list of worlds; the state in the bundle
is safe-guarded by the server until the next event; and the mails are
broadcast as specified.
The following picture provides a graphical overview of the server's workings. The following picture provides a graphical overview of the server's workings.
@ -1039,36 +1045,37 @@ optional handlers:
@item{ @item{
@defform/none[(on-tick tick-expr) @defform/none[(on-tick tick-expr)
#:contracts #:contracts
([tick-expr (-> (unsyntax @tech{UniverseState}) bundle?)])]{ ([tick-expr (-> [listof world?] (unsyntax @tech{UniverseState}) bundle?)])]{
tell DrScheme to apply @scheme[tick-expr] to the current state of the tell DrScheme to apply @scheme[tick-expr] to the current list of
universe. The handler is expected to produce a bundle of the new state of participating worlds and the current state of the
the universe and a list of mails. universe.
} }
@defform/none[(on-tick tick-expr rate-expr) @defform/none[(on-tick tick-expr rate-expr)
#:contracts #:contracts
([tick-expr (-> (unsyntax @tech{UniverseState}) bundle?)] ([tick-expr (-> [listof world?] (unsyntax @tech{UniverseState}) bundle?)]
[rate-expr natural-number/c])]{ [rate-expr natural-number/c])]{
tell DrScheme to apply @scheme[tick-expr] as above but use the specified tell DrScheme to apply @scheme[tick-expr] as above but use the specified
clock tick rate instead of the default. clock tick rate instead of the default.
} }
} }
@item{ @item{
@defform[(on-disconnect dis-expr) @defform[(on-disconnect dis-expr)
#:contracts #:contracts
([dis-expr (-> (unsyntax @tech{UniverseState}) world? bundle?)])]{ ([dis-expr (-> [listof world?] (unsyntax @tech{UniverseState}) world? bundle?)])]{
tell DrScheme to invoke @scheme[dis-expr] every time a participating tell DrScheme to invoke @scheme[dis-expr] every time a participating
@tech{world} drops its connection to the server. The first argument is the @tech{world} drops its connection to the server. The first two arguments
current state of the universe; the second one is the world that got are the current list of participating worlds and the state of the
disconnected. universe; the third one is the world that got disconnected.
} }
} }
@item{ @item{
@defform[(to-string render-expr) @defform[(to-string render-expr)
#:contracts #:contracts
([render-expr (-> (unsyntax @tech{UniverseState}) string?)])]{ ([render-expr (-> [listof world?] (unsyntax @tech{UniverseState}) string?)])]{
tell DrScheme to render the state of the universe after each event and to tell DrScheme to render the state of the universe after each event and to
display this string in the universe console. display this string in the universe console.
} }
@ -1179,18 +1186,18 @@ translates into the design of two functions with the following headers,
@(begin @(begin
#reader scribble/comment-reader #reader scribble/comment-reader
(schemeblock (schemeblock
;; @tech{UniverseState} world? -> (make-bundle @tech{UniverseState} [Listof mail?]) ;; @tech{UniverseState} world? -> (make-bundle [Listof world?] @tech{UniverseState} [Listof mail?])
;; create new @tech{UniverseState} when world w is joining the universe, ;; create new @tech{UniverseState} when world w is joining the universe,
;; which is in state s; also send mails as needed ;; which is in state s; also send mails as needed
(define (add-world s w) ...) (define (add-world s w) ...)
;; @tech{UniverseState} world? MsgW2U -> (make-bundle @tech{UniverseState} [Listof mail?]) ;; @tech{UniverseState} world? MsgW2U -> (make-bundle [Listof world?] @tech{UniverseState} [Listof mail?])
;; create new @tech{UniverseState} when world w is sending message m ;; create new @tech{UniverseState} when world w is sending message m
;; to universe in state s; also send mails as needed ;; to universe in state s; also send mails as needed
(define (process s p m) ...) (define (process s p m) ...)
)) ))
Note how both functions return a bundle. Note how both functions return a @emph{bundle}.
Finally, we must also decide how the messages affect the states of the Finally, we must also decide how the messages affect the states of the
worlds; which of their callback may send messages and when; and what to do worlds; which of their callback may send messages and when; and what to do
@ -1272,7 +1279,7 @@ The preceding subsection dictates that our server program starts like this:
#reader scribble/comment-reader #reader scribble/comment-reader
[schemeblock [schemeblock
;; Result is ;; Result is
;; (make-bundle UniverseState (list (make-mail world? GoMessage))) ;; (make-bundle [Listof world?] UniverseState (list (make-mail world? GoMessage)))
;; UniverseState world? -> Result ;; UniverseState world? -> Result
;; add world w to the universe, when server is in state u ;; add world w to the universe, when server is in state u
@ -1298,14 +1305,14 @@ The second step of the design recipe calls for functional examples:
[schemeblock [schemeblock
;; an obvious example for adding a world: ;; an obvious example for adding a world:
(check-expect (check-expect
(add-world '() world1) (add-world '() '* world1)
(make-bundle (list world1) (make-bundle (list world1) '*
(list (make-mail world1 'it-is-your-turn)))) (list (make-mail world1 'it-is-your-turn))))
;; an example for receiving a message from the active world: ;; an example for receiving a message from the active world:
(check-expect (check-expect
(switch (list world1 world2) world1 'it-is-your-turn) (switch (list world1 world2) '* world1 'it-is-your-turn)
(make-bundle (list world2 world1) (make-bundle (list world2 world1) '*
(list (make-mail world2 'it-is-your-turn)))) (list (make-mail world2 'it-is-your-turn))))
]) ])
@ -1327,7 +1334,7 @@ message to the first world on this list to get things going:
[schemeblock [schemeblock
(define (add-world univ wrld) (define (add-world univ wrld)
(local ((define univ* (append univ (list wrld)))) (local ((define univ* (append univ (list wrld))))
(make-bundle univ* (make-bundle univ* '*
(list (make-mail (first univ*) 'it-is-your-turn))))) (list (make-mail (first univ*) 'it-is-your-turn)))))
]) ])
@ -1346,7 +1353,7 @@ Similarly, the protocol says that when @emph{switch} is invoked because a
[schemeblock [schemeblock
(define (switch univ wrld m) (define (switch univ wrld m)
(local ((define univ* (append (rest univ) (list (first univ))))) (local ((define univ* (append (rest univ) (list (first univ)))))
(make-bundle univ* (make-bundle univ* '*
(list (make-mail (first univ*) 'it-is-your-turn))))) (list (make-mail (first univ*) 'it-is-your-turn)))))
]) ])