Teachpacks for How to Design Programs

# Simplified Scheme Web Servlets

### servlet2.ss

This teachpack provides a simplified API for PLT Scheme servlets. The teachpack does not require any understanding of HTML and higher-order functions. It uses structures and lists, and is therefore well-suited for use with an HtDP course.

### Interface

       ; Data Constructors  -------------------------------------------------------
       make-password ; asking for a password
       make-number   ; asking for a number
       make-yes-no   ; asking for a Yes-No style answer
       make-boolean  ; asking for a true-false style answer
       make-radio    ; requesting one choice from some mutually exclusive choices

       #| Data Definitions --------------------------------------------------------

       Forms ----------------------------------------------------------------------
       Query    = (union String
                    (make-password String)
                    (make-number   String)
                    (make-boolean  String)
                    (make-yes-no   String String String)
                    (make-radio    String (cons String (listof String))))
       FormItem = (list Symbol Query)
       Form     = (cons FormItem (listof FormItem))

       Table -------------------------------------------------------------------
       Response = (union String Number Boolean)
       Table    = (listof (list Symbol Response))
       |#

       ; Functions ----------------------------------------------------------------

       form?               ; TST -> Boolean
       ; checking the structure of forms

       form-element?       ; TST -> Boolean
       ; checking the structure of form-elements

       single-query        ; Query -> Response
       ; posing a single question

       queries             ; (listof Query) -> (listof Response)
       ; posing a list of questions

       echo-answers        ; (listof Response) -> true
       ; echoing the answers from a list of questions to a Web page (development)

       form-query          ; Form -> Table
       ; posing a list of questions with tag

       extract/single      ; Symbol Table -> Response
       ; extracting the answer for a given tag from a response; the tag must
       ; occur exactly once.

       extract             ; Symbol Table -> (listof Response)
       ; extracting all the answers for a given tag from a response; the list
       ; is empty if there is no such tag.

       echo-response       ; Table -> true
       ; echoing the response from a form to a Web page (development)

       inform              ; String String *-> true
       ; posting some information on a Web page, wait for continue signal

       final-page          ; String String *-> true
       ; posting some information on a Web page,
       ; killing the script and all associated backtrack/clone points

### Pragmatics

The following table specifies what kind of answer each form of query produces:

      Query                                      GUI Item         Response
    ________________________________________________________________________________
      String                                     text field       String
      (make-password String)                     password field   String
      (make-number   String)                     text field       Number
      (make-boolean  String)                     check box        Boolean
      (make-yes-no   String String1 String2)     2-pronged radio  String1 or String2
      (make-radio    String loString)            radio button     one of loString
      (make-button   String0)                    submit button    String0

The functions play the following role:

- `form?` and `form-element?` enable programmers to check the well-formedness of their queries.
- `single-query` poses a question and waits for a answer from the consumer.
- `queries` poses a list of questions and waits for the submission of answers; it produces a list of answers that is as long as the list of given questions.
- `echo-answers` echoes a list of answers to a Web page; this function is useful for testing Web form designs.
- `form-query` poses a form with queries and waits for the submission of answers; it produces a list of tagged or labeled answers that is as long as the list of given questions.
- `echo-response` echoes a response to a Web page as a table.
- `inform` posts some information on a Web page and wait for a continue signal (a link) from the consumer; the first string plays the role of a title and the rest form a paragraph.
- `final-page` posts some information on a Web page and shuts down the script and all associated backtrack/clone points.

### Example

The following example illustrates how the library enables programs to interact with the consumer. In particular, note the properly recursive calls to `login` in `inform-error`. Also note how the primitives `make-password` and `make-number` deliver strings and numbers, respectively.

    #| Login Site -----------------------------------------------------------------
       Author: Matthias Felleisen
       Language: Intermediate
       Teachpack: servlet2.ss

       Login Web Site:

       A login site consists of three pages:
        1. login: request user information: name, password, year-of-birth
           - if correct, respond with greeting for name
           - if incorrect, go to error page
        2. error: inform user of error, continue goes back to login page
        3. greetings: say hello to name
       The second and third are generated from user input, the first is
       generated by the program alone.

    |#

    ;; Login Page -----------------------------------------------------------------

    ; ask three questions: one plain, one password, one numeric
    (define login-page
      (list
       (list 'name "User Name")
       (list 'pass (make-password "Password"))
       (list 'yofb (make-number "Year-of-birth"))))

    ; Table -> true
    ; process the response for login-page
    (define (login r)
      (let ([name (extract/single 'name r)])
        (if (string=? (lookup-password name) (extract/single 'pass r))
            (if (= (lookup-yofb name) (extract/single 'yofb r))
                (greetings name)
                (inform-error "bad data"))
            (inform-error "bad match"))))

    ; String -> (union false String)
    ; lookup the password for name in DB
    (define (lookup-password name)
      (local ([define (x=? x) (string=? name x)]
              [define r (assf x=? DB)])
        (if (boolean? r) false (second r))))

    ; String -> (union false Number)
    ; lookup the year-of-birth for name in DB
    (define (lookup-yofb name)
      (local ([define (x=? x) (string=? name x)]
              [define r (assf x=? DB)])
        (if (boolean? r) false (third r))))

    (define DB
      '(("matthias" "okay" 1958)))

    ;; Error Page -----------------------------------------------------------------

    ; String -> true
    ; consume error message, print and enable return to login page
    (define (inform-error s)
      (let ([_ (inform "Error" s)])
        (login (form-query login-page))))

    ;; Greetings Page -------------------------------------------------------------

    ; String -> true
    ; consume name and display good bye message
    (define (greetings name)
      (inform "Welcome" "Welcome " name " and good bye."))

    ;; RUN ------------------------------------------------------------------------
    (login (form-query login-page))