[plt-scheme] Feature: Expired-continuation response for send/forward, send/finish

From: Jordan Johnson (jorjohns at cs.indiana.edu)
Date: Sun Nov 21 14:06:07 EST 2004

[Warning: half-baked idea follows.  May need further baking.]

One thing I find I keep wanting to do is install a failure-continuation 
for when users accidentally reload a form or use the back button; it's 
needlessly frustrating for them to see "The transaction referred 
to...has expired", and I've mostly abandoned use of send/forward for 
that reason, though I like the concept of it.

So, I was thinking, perhaps send/forward could be modified somehow, 
such that when called with one argument it maintains its current 
behavior, but if called with a second procedure, it points all the 
session's defunct k-urls to that procedure as a continuation, rather 
than purging them?

It seems to me that such a continuation might expect a request; or 
perhaps, simply, that it could receive the same k-url generated by 
send/forward for the last valid page, since the only sensible thing to 
do with a request for an expired k-url would be to ignore its bindings.

Following is an example of one way it might be used, but first, the 
caveat:  I'm not pleased with the way that this example would lead to 
semi-CPS'd code.  I know there's got to be a better way to do it.  
Still, I feel a need for a construct that addresses this, and I hope my 
description and example get the point across.

;;;;;
;; not defined here:
;; make-question-widget: question-struct -> xexpr
;; correct?: question-struct answer -> boolean
;; request->answer unpacks an answer from the bindings in a request.

;; question-struct (req -> void) -> answer
(define (get-user-answer question bad-user-k)
   (request->answer
     (send/forward
       (lambda (k-url)
        `(html
           (body
             (form ((action ,k-url) (method "POST"))
               ,(make-question-widget question)
               (input ((type "submit") (name "submit") (value 
"submit")))))))
       bad-user-k)))

;; (listof question-struct) -> void
(define (quiz-servlet loq)
   (send-start-page)
   (let loop ((questions-left loq)
              (number-answered 0)
              (incorrect '()))
     (if (null? loq)
       (send-end-page answered incorrect)
       (let* ((question (car loq))
              (answer (get-user-answer
                        (car loq)
                        (lambda (req)    ;; here's the new user-error 
continuation
                          (send/suspend  ;; (which would have to escape, 
yes)
                            (lambda (k-url)
                              `(html
                                 (body
                                   (p "Sorry, you may not go back, only "
                                      (a ((href ,k-url)) "forward") 
".")))))
                          (loop loq number-answered incorrect)))))
        (if (correct? question answer)
          (loop (cdr loq) (add1 number-answered) incorrect)
          (loop (cdr loq)
                (add1 number-answered)
                (cons question incorrect)))))))

;;;;;

Is there some merit in this?  Has it been discussed already?  Or is 
there an existing mechanism I could be using instead?

jmj

: Jordan Johnson - jorjohns @ cs . indiana . edu
: Thrive defensively.



Posted on the users mailing list.