[racket] Engineering Tradeoffs of ANF transforms and the Stateless Server

From: Robby Findler (robby at eecs.northwestern.edu)
Date: Sat Dec 31 21:36:41 EST 2011

FWIW, this is essentially re-implementing dynamic-wind (but it is not
too difficult if you are familiar with continuations). One thing to
watch out for: the lists of continuation marks will, in some cases,
share a tail. In that case you'll want to avoid exiting and
re-entering the same things. Also worth noting here, I think, you may
need to use some kind of unique values in the marks to be able to tell
if the shared tails _really_ are shared or if they simply have the
same structure.

You might find this paper useful to sort out some of the subtleties:



On Sat, Dec 31, 2011 at 8:18 PM, Galler <lzgaller at optonline.net> wrote:
> Robby,
> Thanks
> Not at all opaque. I was experimenting with that earlier this afternoon, as
> below.
> Actuallly, the way you phrased it helps clarify something I was struggle
> with.
> A very useful and valuable suggestion.  I think that may very well be plan
> B.
> R./
> Zack
> (define (nextproc)
>  ;need an intermediate function, or it will replace prior mark (tail-calling
>  (list
>   (with-continuation-mark 'state '(S2 beforeproc afterproc) ((λ ()
>                                                                (printf "in
> S2 ~A\n" (continuation-mark-set->list
> (current-continuation-marks) 'state)))))
>   (with-continuation-mark 'state '(S3 beforeproc afterproc) ((λ ()
>                                                                (printf "in
> S3 ~A\n" (continuation-mark-set->list
> (current-continuation-marks) 'state)))))))
> (with-continuation-mark 'state '(S1 beforeproc afterproc) (nextproc))
> On Sat, Dec 31, 2011 at 9:03 PM, Robby Findler wrote:
>> I'm not sure if the web-server supports continuation marks or not, but
>> if it does, you could use continuation marks to note what the exit and
>> entry operations are, and then when you would do a continuation jump,
>> first grab the continuation marks from one side, do the jump, grab the
>> continuation marks from the other side, and then explicitly do the
>> actions that the marks have recorded should be done. (Let me know if
>> that is too opaque ...)
>> Robby
>> On Sat, Dec 31, 2011 at 7:56 PM, Galler <lzgaller at optonline.net> wrote:
>>> Sorry, should have included a brief example.
>>> Here's an example of what I've implemented, which is just Harel's
>>> hierarchical state machines
>>> You can create a Hierarchical State Machine by defining individual nodes
>>> in
>>> a flat file, as below.
>>> each node has 6 keyword parameters , state, parent, entry, init, exit,
>>> and a
>>> handler.
>>> The machine is very much like a web-server. It receives a signal (akin to
>>> a
>>> request), processes the signal which may cause a change internal state,
>>> and
>>> returns a continuation to be invoked when the next signal is presented.
>>> The new signal is the argument provided to this continuation at
>>> invocation.
>>> In the stateful server, the  HSM continuation is closed over by the PLT
>>> Server's external continuation (reified by send/suspend)
>>> In the stateless version, I would replace the HSM continuation with the
>>> PLT
>>> server's continuation (reified by send/suspend).
>>> I can't do that right now because the continuation is in the scope of the
>>> dynamic-wind function, which is an unsafe place to capture continuations
>>> for
>>> #lang web-server
>>> The dynamic wind is used as follows:
>>> At present, the nodes are brought into the correct tree-like dynamic
>>> extent
>>> by a recursive function which invokes dynamic-wind.
>>> Note that the handler code supports jumping to another state  (trans 'S2
>>> 'S3).
>>> Trans invokes a continuation reified earlier associated with state S3. In
>>> this case, the invocation of the continuation calls the exit actions of
>>> state S2 and the entry actions of S3.
>>> That's where the dynamic-wind comes in. Its necessary for transitions
>>> between states and but used for anything else.
>>> That's why I think an overridden call/cc-dynamic-wind and dynamic wind
>>> would
>>> be sufficient.
>>> (defnode
>>>  #:state 'S2
>>>  #:parent 'Top
>>>  #:entry  (λ () (I-TLL:entry-start-TLL))
>>>  #:init (lambda () (trans 'S2 'S3))
>>>  #:exit  (λ () (I-TLL:exit-secure-TLL))
>>>  #:handler (λ (signal)
>>>              (cond
>>>                [(signal-eq? signal "main") (trans 'S2 'S3)]
>>>                [(signal-eq? signal "info") (trans 'S2 'S4)]
>>>                [(signal-eq? signal "about") (trans  'S2 'S5)]
>>>                [(signal-eq? signal "item") (trans 'S2 'S6)]
>>>                [(signal-eq? signal "field") (trans 'S2 'S7)]
>>>                [(signal-eq? signal "dispatch") (trans  'S2 'S8-3)]
>>>                [(signal-eq? signal "burden") (trans  'S2 'S8-2)]
>>>                [(signal-eq? signal "planning") (trans 'S2 'S8-1)]
>>>                [(signal-eq? signal "failentry") (trans 'S2 'S3)]
>>>                [else #f])))
>>> ____________________
>>>  Racket Users list:
>>>  http://lists.racket-lang.org/users

Posted on the users mailing list.