A web-based teaching application

I was inspired by the way “The Little Schemer” was used to teach scheme, with question on the left and answers on the right. I wondered how hard it would be to build a web app that could teach you in such an interactive way. Not so hard as I later found out, it needed less than 70 lines of code to build a prototype. Not only is the code small, but all you need to do is create a “nodes” datatype to create your own custom book! 

The application first starts with a list of nodes. Each node contains a question to ask and possible responses. Each response can either do nothing (i.e. you move on to the next node in the list), jump you to another named node or have their own child nodes that only they can visit. Each node may or may not have a label, so we can only use them when we need to jump. 

Here’s a small example that tries to teach you French.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 
#lang racket
(require web-server/servlet)
(require web-server/servlet-env)


; a teaching web thingy where you can create your own custom teaching libraries.
;
;
; let's call an ask-response an askonce
; askonse contains ask and response
;
; ask can contain text, pics or combinations of either.
;
; response can contain text, and choices.
;
;
; each askonse can have a label so that you can get back to it later.
;
; each response leads to another askonse.
;
; How would it be structured?
;
; 1. you should be able to ask questions and save them to variables.
;
; for eg. you could ask a persons name and reuse it to address the person later on.
;
; askonce -> list of nodes
; ask/responsetext -> some html markup thingy
; car of node -> ask
; cdr of node -> list of possible responses
; last of node (optional) -> label for node
; car of response -> responsetext
; cdr of response (optional) if atom -> go to label
; cdr of response (optional) if list -> a node
;
;
; if no cdr of a response exists, then it moves to the next askonce
;
;
;
;
;


(define nodes
  '(("how do you do?" (("not bad! how about you?")) home)
    ("I'm fine thank you!!"
     (("I don't really care!!" home)
      ("you're welcome")))
    ("Bonjour" (("Bonjour! Is that French?")) bonjour)
    ("Oui! Bonjour means 'good morning' in French"
     (("Ahh! Je comprend!")))
    ("What do you think 'bon' in bonjour means?"
     (("umm I don't know..." ("it means 'good'" (("ahh.."))))
      ("I guess it means good" ("awesome" (("thanks"))))) complicatednode)
    ("Ok now what might 'jour' mean?"
     (("night" ("not quite" (("sorry.."))))
      ("day! it means day!" ("awesome" (("thanks!"))))))
    ("too complicated"
     (("yes!" bonjour)
      ("not really")))))

(define (start request)
  (show-nodes nodes request))
  
(define atom?
   (lambda (x)
     (cond
       ((null? x) #f)
       ((pair? x) #f)
       (else #t))))

(define (response-text r) (car r))

(define (find-node lbl)
    (local [(define (find-lbl n)
              (if (null? n) '()
                  (let ((lblname (last (car n))))
                    (cond
                      ((and
                        (atom? lblname)
                        (eq? lblname lbl)) n)
                      (else (find-lbl (cdr n)))))))]
      (find-lbl nodes)))
             

(define (node-ask n) (first n))
 
(define (response-action r)
  (if (pair? (cdr r))
      (cadr r)
      '()))
 
(define (node-responses n)
  (second n))

(define (node-label n)
  (let ((lbl (last n)))
    (if (atom? lbl)
        lbl
        'empty-label)))

(define (has-label? n)
  (eq? 'emtpy-label (node-label n)))
      
(define (show-nodes n request)
  (local [(define (current-node) (car n))
          (define (response-generator embed/url)
            `(html (head (title "Graph Traversal example"))
                   (body
                    (p ,(node-ask (current-node)))
                    ,@(map (lambda (r)
                             `(p(a ((href ,(embed/url (new-node-location r)))) ,(response-text r))))
                           (node-responses (current-node))))))
          (define (new-node-location resp)
            (let ((action (response-action resp)))
              (cond
                ((null? action) (lambda (req) (display 'is-null) (show-nodes (cdr n) req)))
                ((atom? action) (lambda (req) (display 'is-atom) (show-nodes (find-node action) req)))
                ((pair? action) (lambda (req) (display 'is-pair) (show-nodes (cons action (cdr n)) req))))))]
    (send/suspend/dispatch response-generator)))

(serve/servlet start #:quit? #t
               #:listen-ip #f
               #:servlet-path ""
               #:servlet-regexp #rx""
               #:port 8000)

Output:

This is the first page after you run the application. It shows the question of the first node. Since its response does not contain any action, it simply creates a link to the next node. 

[[posterous-content:pid___0]] 

This page for the second node. There are two possible responses, either you say “I don’t care” which takes you back to the “home” node while clicking on “you’re welcome” takes you to the next node. 

 

[[posterous-content:pid___1]]

 

Let’s skip the next node as it only has one response. Now the fourth node contains two responses each of which sends you to a different node.

[[posterous-content:pid___2]]

If you click on “umm I don’t know…” , you get to this page.

[[posterous-content:pid___3]]

 

and if you click on “I guess it means good” link, you get to this page. 

[[posterous-content:pid___4]]

 

Since, none of the responses above do anything more clicking any of the two link above takes you to the page for the next node. 

 

Enjoy.

 

One thought on “A web-based teaching application

Leave a comment