[plt-scheme] using continuations for an async protocol
Daniel Silva wrote:
> ;; iq-set: JabberClient x-expression -> sxp
> (define (iq-set client query-xexpr)
> ;; generate an id, but not a gensym.. so wrap it in a string
> (let ([id (format "~a" (gensym 'iqset))])
> (let/cc k
> (hash-table-put! *conts* (string->symbol id) k)
> ;; send the tagged query message to the jabber server
> (jwrite client `(iq ([type "set"]
> [id ,id])
> ,query-xexpr))
> ;; suspend?
> (update client))))
>
>Where jwrite sends an x-expression to a jabber client, and update is:
>
> (define (update client)
> (let* ([xexpr (jread client)] ;; read incoming message
> [id (a-lookup 'id xexpr)]) ;; find its id, if it has one
> (if id
> (let* ([key (string->symbol id)]
> [k (hash-table-get *conts* key)]) ; find the stored k
> (hash-table-remove! *conts* key) ; clean up
> (k xexpr))
> (begin (dispatch xexpr) ;; dispatch untagged messages
> (update client))))) ;; rinse, repeat
>
I am assuming dispatch sends the xexpr to a function that handles it.
That function may call update either directly or indirectly (by calling
iq-set). I can see some trouble if that happens given that (dispatch
xexpr) is not a tail call. You may see it more clearly if we write
update as
(define (update client)
(let ([xexpr (jread client)]) ;; read incoming message
(begin
(dispatch xexpr) ;; dispatch untagged messages
(update client)))) ;; rinse, repeat
;;; inlining dispatch may make update look like this:
(define (update client)
(let ([xexpr (jread client)]) ;; read incoming message
(begin
(case-xexpr xexpr
[(welcome) (begin do-some-stuff-that-result-in (update client))]
[(join) (begin do-some-other-stuff (update client))]
[...])
(update client))))
;;; and possibly this:
(define (update client)
(let ([xexpr (jread client)]) ;; read incoming message
(begin
(case-xexpr xexpr
[(welcome) (begin do-some-stuff)]
[(join) (begin do-some-other-stuff)]
[...])
(if some-consition (update client))
(update client))))
;;; or this:
(define (update client)
do-something
(if some-condition (update client))
(update client))
So, your memory requirements are unbounded. I would recommend
formulating the problem as coroutines so that control jumps back and
forth between your dispatch calls and your update function instead of
having update continuously running in a a loop.
Aziz,,,