Lab 7h S-expressions
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.
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.
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.
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: | ||||||||
|
(define wp-page '(html (head (title "My first generated web page")) (body (p "This is my first generated web page. More to come"))))
open a lab specific teachpack in your browser
download the file to the folder for this lab;
- create a lab-7 file and addto 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.)
(write-file "1.html" (xexpr-as-string wp-page)) (show "1.html")
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.
; 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.
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!
; 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
The teachpack that you installed comes with a
function—
> (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.
(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
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).
If you’re done early
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.
`(a ((href ,(file-name n))) ,(title-of-song n))
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.
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.