[plt-scheme] Feature: Expired-continuation response for send/forward, send/finish
[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.