On this page:
Partner Switch
The Glory of the Sexpr
Sexprs in Practice, A First Glance
Simultaneous Processing
If you’re done early
Before you go...

Lab 7h S-expressions

home work!

Purpose In this lab we’re going to work with S-expressions, a type of data that you’ve already used quite a bit informally. We’ll slice up lists with unquote-splicing and reach outside our walled garden to touch the file system for the first time.

image

Partner Switch

TAs: prepare partnering

It is time for another partner. Unlike in a company, where you may switch partners twice a day, we just switch three times over the course of the semester. This time the head TAs are picking partners for you in the hope of finding good matches.

To ensure that the partnerships are working out for the last five weeks, each of you must:
  • keep a diary of partner interactions; record when you meet, what you work on, what your next meeting date is;

  • report problems to the head TA of your lab; and

  • meet with your instructor concerning repeat problems.

image

The Glory of the Sexpr

You’ve written quite a bit of code in BSL and ISL. Take any (syntactically valid) expression you’ve written to date, toss a ’ in front, and what do you have? It’s an S-Expression:

; An S-Expression (or Sexpr) is one of:
; - Symbol
; - String
; - Number
; - [Listof Sexpr]

Examples:

> "hello!"

"hello!"

> '(1 2 3)

'(1 2 3)

> '(define (insult name)
     (string-append "You're dumb, " name "."))

'(define (insult name) (string-append "You're dumb, " name "."))

What you didn’t know is that many S-expressions are also good for coding web pages. The source code for a page is XHTML (a flavor of XML), and we represent such codes with special S-expressions. For example,
(define wp-page
  '(html
     (head
       (title "My first generated web page"))
     (body
       (p "This is my first generated web page. More to come"))))
is a simple web page that consists of a title and a body.

You can translate this XHTML representation into a string, write to a file, and show it in a browser. To do so,
  • open a lab specific teachpack in your browser

  • download the file to the folder for this lab;

  • create a lab-7 file and add
    (require "lab8-teachpack.rkt")
    (require 2htdp/batch-io)
    to the definitions area and save it in a file. (The 8 is not a typo unless you rename it to "lab7-teachpack.rkt" when you download.)

Once you have that, add these lines to your wp-page definition:
(write-file "1.html" (xexpr-as-string wp-page))
(show "1.html")
The last expression is the first command you see in this course; it opens a browser tab and points it to the file you just wrote.

Let’s try to generate the second, third, ..., 200th web page. You see, you don’t want to generate these by hand. You want to abstract over the above web page. Doing so calls for a function and some good way of writing down schemas for web pages.

With quote alone, this won’t be easy and cons or list are to cumbersome. Yes, quasiquote and unquote are your friends:
; Nat -> Sexpr
; generate the nth web page
(define (my-nth-page n)
  (local ((define n-as-string (number->string n)))
    `(html
       (head
         (title
           ,(string-append "My " n-as-string " generated web page.")))
       (body
         (p
          ,(string-append "This is my "
                          n-as-string
                          " generated web page. More to come."))))))

Time to program

Exercise 1 Design a function that consumes a natural number and generates a file name with a ".html" extension.

Exercise 2 Design a function that consumes a natural number n, generates your nth web page, and writes it to a an ".html" file.

The tests for this function are not sufficient to check the entire result because it writes to a file as a side-effect. Use show from the teachpack to view the page(s) you generate with the tests.

Exercise 3 Design a function that consumes a natural number n and creates that many web pages in your directory, named "1.html", "2.html", and so on. The function returns the list of file names, assuming the files have been created successfully.

Once the function successfully passes its test, use show to look at one of the generated web pages.

Exercise 4 Design the function replace-symbol, that given a Symbol and two Sexprs, replaces any instance of the Symbol in the second Sexpr with the first Sexpr.

image

Partner switch

Sexprs in Practice, A First Glance

Your professors have been quite busy this semester. Not only do they teach and slave away on research, but they’ve been working on digital music software: picture iTunes with more parentheses. Their start-up, λTunes, is about to be acquired by Google for just under a billion dollars, but the deal is stalled because Professor Van Horn forgot to implement an HTML generator for playlists . Let’s help him out!

Your professors have provided their favorite playlists for you to work with.
When you click on one of these links, you see files in a language that looks like XHTML but it is actually a form of XML, a generalization of the markup language. Again, it has a convenient representation as S-expressions:
; All PlayXexprs are of the form:
;    (cons 'playlist (cons [Listof Attribute] [Listof SongXexpr]))
; where the only Attribute is associated with 'name.
; Interpretation: a PlayXexpr is a data representation for playlists
; 
; All SongXexprs are of the form:
;    (cons 'song (list [Listof Attribute]))
; where the valid Attributes are: 'album, 'artist, 'title, and 'year
; Interpretation: a SongXexpr is a data representation for songs in a playlist
; 
; An Attribute is a:
;   (list Symbol String)
; Interpretation: '(a "b") represents the attribute
; a = "b" in a piece of XML data
Now download these files but save them as ".xml" files. That is, save each of these files in the same folder as your Lab 7 program file.

The teachpack that you installed comes with a function—read-xexprthat can read these files. When you have downloaded the files, make sure they are available:

> (read-plain-xexpr "lab7-ahmed.xml")

read-plain-xexpr: expects a name of file in program's folder

as first argument, given "lab7-ahmed.xml"

Some Xexprs contain a list of Attributes. A list of Attributes is a list of two element lists. Each of the internal lists has a Symbol as the first element and a String as the second element. This is a fairly common pattern in Sexpr-based languages called an association list.

Exercise 5 Design the function retrieve, which given a list of Attributes and a Symbol returns the String content associated with that Symbol. If the Symbol is not a valid attribute, the function may raise an error and/or return false.

Exercise 6 Using retrieve and map, design the function all-songs, which consumes a PlayXexpr and produces a list of all song titles (Strings).

Hints How can you extract the list of SongXexprs from a PlayXexpr? If SongXexpr were a structure, you would have the function playlist-songs available.

Where is the Attribute list in a SongXexpr? If SongXexpr were a structure, you would have the function song-attributes available.

When you have a song list, you can make a web page per song. Here is a page for the first song on Prof. Ahmed’s play list:
(define song-page
  '(html
    (head
     (title "Shine on You Crazy Diamond, Pts. 1-5"))
    (body
     (p "This is the web page for:")
     (p "Shine on You Crazy Diamond, Pts. 1-5"))))

Exercise 7 Define a function that creates a web page representation for a song title.

We use the word “define” here because you are generalizing from an S-expression, just like we did above. What would change in song-page if we wanted to use the second song on Prof. Ahmed’s list?

This exercise will require a hint from the TA. Please do experiment using the design recipe as rigorously as possible for the critical auxiliary function.

Exercise 8 Design a function that creates one web page representation per song on a playlist, writes it as a string to a numbered file (see file-name above), and returns the list o file names.

Use show to look at some of the pages you created.

Phew! If you’ve made it this far, give yourself a pat on the back. You have just seen the rudimentary idea of how to generate an on-line store.

Simultaneous Processing

image

Recall Student from the previously lab:

(define-struct student (name grade))
; A Student is a (make-student String Number)
; interpretation: (make-student n g) represents a student
;  whose name is n and whose grade is g
 
; Examples:
(define student1 (make-student "Claire" 95))
(define student2 (make-student "Brad" 65))
(define student3 (make-student "Sara" 87))

The Head TA of fundies uses a similar structure to keep track of all the students in the course, their contact information, and their grades:

; A BetterStudent is a (make-student Symbol String MaybeGrader Natural)
; interp: (make-student username email grader grade) represents a
;   student whose MyNEU username is username, email address is email,
;   grader is grader, and total points is grade
(define-struct student (username email grader grade))
 
; Examples:
(define testy-student
  (make-student 'testy-tester "testy-tester@testy.tester" false 1000))
 
; A MaybeGrader is one of:
; - false
; - (make-grader Symbol String)
; interp: false indicates a grader has yet to be assigned, while a
;   (make-grader user email) represents a grader whose MyNEU username is
;   user and contract email address is email.
(define-struct grader (user email))
 
; Examples:
(define fake-grader false)
(define the-best-grader
  (make-grader 'wilbowma "wilbowma@totally.bogus"))
 
; A Roster is a [List-of BetterStudent]
 
; Examples:
(define ta-roster
  (list (make-student 'wilbowma "wilbowma@totally.bogus" false 0)
        (make-student 'calvis "calvis@totally.bogus" false 9001)))

Unfortunately, following the chaos of grading exams, the Head TA lost the Roster, and everyone’s grades. He hasn’t had time to fix it, because this week he has to design a lab. Being a big fan of meta, he decides to design a self-referential lab in which his students help fix the roster.

Recall that XHTML can be parsed as XML.

Exercise 9 Write a function read-roster that takes a String representing an HTML file such as lab7h-roster.html and returns a Roster. Ensure every student starts with 0 points. (Don’t you dare give yourself extra points!).

To help with examples and tests for this, use the following functions:

; Natural -> Xexpr
; Roster generates an HTML roster with bogus student information.
(define (gen-roster n)
  `(html
    (head (title () "Roster"))
    (body
     (table
      (tr (td () "Student Name") (td () "Username") (td () "Student ID"))
      ,@(build-list
         n
         (lambda (x)
           (local [(define name
                     (format "First ~a. Last" x))
                   (define username
                     (format "student.n~a" x))
                   (define mailto
                     `(a ((href ,(format "mailto:~a@husky.neu.edu" username))) ,name))]
             `(tr (td ,mailto)
                  (td () ,username)
                  (td () ,(format "~a" x))))))))))
 
 
(check-expect (xexpr? (gen-roster 0)) true)
(check-expect (xexpr? (gen-roster 5)) true)
 
(define (gen-html-roster n) (xexpr-as-string (gen-roster n)))
Hint 1: HTML is very nested in order to represent how things are displayed on the screen, but this can make finding data in it difficult.

Hint 2: You might find these definitions useful:

; An AXexpr is a:
; (list 'a (list Href) String)
; interp: (list 'a (list Href) name) is an entry from an
;   Xexpr representation of an HTML roster, where name is the student's
;   name and Href is the mailto link.
 
; A Href is a (list 'href String)
; interp: (list 'href mailto) where mailto contains an email address
;   prefixed with "mailto:"
 
; Href -> Symbol
; Parses the student's username
(define (href->username href)
  (local [(define email (href->email href))
          ; [List-of Strings] -> [Maybe Natural]
          (define (find-element-index ls)
            (cond
              [(empty? ls) #f]
              [(cons? ls)
               (if (string=? "@" (first ls))
                   0
                   (add1 (find-element-index (rest ls))))]))]
    (string->symbol (substring email 0 (find-element-index (explode email))))))
 
(check-expect (href->username '(href "mailto:wilbowma@totally.biogus")) 'wilbowma)
 
; Example:
(check-expect
 (read-roster "lab7h-roster.html")
 (build-list
  60
  (lambda (x)
    (local [(define username (string->symbol (format "student.n~a" x)))]
      (make-student (format "~a@husky.neu.edu" username) username false 0)))))

Because they’re so easy to work with, your Head TA stores grades for problem sets, exams, and quizzes using S-exprs:

; A Graded is a [List-of StudentGradePair]
 
; A StudentGradePair is a (list Symbol Natural)
; interp: (list s n) represents a grade of n for the student whose MyNEU
;   username is s.
 
; Examples:
(define ta-quiz '((wilbowma 0) (calvis 1)))

Exercise 10 Design the function lookup-grade which takes a Symbol representing a student’s username and a Roster, and returns the student’s grade. For a challenge, do it in one line.

(check-expect (lookup-grade 'wilbowma ta-roster) 0)
(check-expect (lookup-grade 'calvis ta-roster) 9001)

Exercise 11 Write a function update-grades that takes a Roster and a Graded and returns a Roster with all students grades updated. Use (require "lab7h-graded.rkt"), which defines exam1, a Graded representing exam1 grades. Download it from here.

(check-expect
 (update-grades ta-roster ta-quiz)
 (list (make-student 'wilbowma "wilbowma@totally.bogus" false 0)
       (make-student 'calvis "calvis@totally.bogus" false 9002)))

Exercise 12 Write the function post-to-handin which takes a roster and returns a list of filenames. Each filename should based on a student’s username, for example, "wilbowma.html". The function should also create each of these HTML files. For example, "wilbowma.html" should contain something like:

<html>

<head>

  <title> Grades </title>

</head>

<body>

<table>

  <tr><td>Username</td> <td>Grade</td></tr>

  <tr><td>wilbowma</td> <td>0</td></tr>

</table>

</body>

</html>

Use xexpr-as-string and write-file. For a challenge, make this one line (not including helpers).

image

If you’re done early

We again proceeded like mini-scientists. The "store" pages we created are absolutely minimal. Here are some ideas on how to refine the program:
  • Consider adding information to each page using extra paragraphs (p).

  • Consider creating pages for entire albums. They should list the title of the album, the artist, and the songs.

  • Consider creating pages for artists. They should list the artists and the albums.

If you know some XHTML and wish to interlink these pages, you can use

`(a ((href ,(file-name n))) ,(title-of-song n))

to create a link from one HTML file to another.

Most students want more information than a raw number of points. Redesign the data definitions for Graded and BetterStudent so you can change post-to-handin to display each student’s course grade as a letter grade, and display the letter grade for each Graded.

image

Before you go...

We’ve got one test behind us. If you bombed it, now is the time to sink or swim. Once the next test passes, those who are failing will have failed and it will be too late to help. If you had trouble finishing any of the exercises in this lab or your homework, or just feel like you’re struggling with any of the class material, come to office hours and talk to a TA or tutor for additional assistance.