This document follows on from Part One and Part Two. You should read those documents first to get an understanding of this one. Part Four extends the framework, adding a callback system, and fixing an important bug. There are no updates to the modal-web-server-0.2.tar.gz file for this part. All the code listed here runs fine in that version.
One problem with the way traditional web applications are structured is that they are quite different from the way standard programs are structured. The following traditional Scheme program prompts the user for two numbers and displays the sum:
(define (add-two-numbers)
(let ((num1 (string->number (get-string "Enter the first number: ")))
(num2 (string->number (get-string "Enter the second number: "))))
(if (and (number? num1) (number? num2))
(show-message (format "The sum of ~a and ~a is ~a" num1 num2 (+ num1 num2)))
(begin
(show-message "You must enter two numbers!")
(add-two-numbers)))))
If the user does not enter a number then the function is re-started to ask for the numbers again. The functions 'get-string' and 'show-message' are simple versions using standard input and standard output to interact with the user:
(define (get-string prompt) (display prompt) (read-line)) (define (show-message msg) (display msg) (newline))
Converting this program to run in a continuation based framework is easy. In fact we can do this with this example without modifying the 'add-two-numbers' function. Instead we only need to write 'web' versions of 'get-string' and 'show-message':
(define (get-string prompt)
(let ((result
(show
(lambda (url)
(sxml->html-string
`(html
(head (title ,prompt))
(body
(form (@ (method "post") (action ,url))
(table
(tr
(td ,prompt)
(td (input (@ (name "string") (type "text") (size "20"))))))
(input (@ (type "submit") (value "ok")))))))))))
(cdr (assoc "string" result))))
This version of 'get-string' displays an HTML page requesting input of a string using an HTML form. It returns the value of the "string" field in that form.
(define (show-message msg)
(show
(lambda (url)
(sxml->html-string
`(html
(head (title ,msg))
(body
(p ,msg)
(a (@ (href ,url)) "Ok")))))))
'show-message' is similar except it doesn't use a form and just displays the message in an HTML page with an 'Ok' anchor. With these two functions replacing the previous console version we can register the 'add-two-numbers' function and access the resulting URL:
(register-function add-two-numbers)
Accessing the URL to run this function will display pages prompting for the two numbers and the resulting page displaying the sum. If numbers are not entered then the first number entry page is re-displayed. There was no need to restructure our original code to cater for the HTTP based request/response model. This technique is discussed in a number of articles on continuation based web applications. A couple that make interesting reading are:
Copyright (c) 2004, Chris Double. All Rights Reserved.