Wednesday, 21 November 2012

Exercise 185: Create the function make-ranking, which consumes a list of ranked song titles and produces an HTML table representation.


Exercise 185: Create the function make-ranking, which consumes a list of ranked song titles and produces an HTML table representation. 

Consider this example:
(define one-list
  '("Asia: Heat of the Moment"
    "U2: One"
    "The White Stripes: Seven Nation Army"))

The type of output expected here isn't really clarified. You could argue we should provide an html string (eg "<html><body>...</body></html>") or the HTML table representation we were given as an example in the previous question. I'm opting for the latter as it matches better the previous question in the book.


(define (ranking los)
  (reverse (add-ranks (reverse los))))

(define (add-ranks los)
  (cond
    [(empty? los) '()]
    [else (cons (list (length los) (first los))
                (add-ranks (rest los)))]))

(define one-list
  '("Asia: Heat of the Moment"
    "U2: One"
    "The White Stripes: Seven Nation Army"))


; draws a single cell of data wrapped in a td
; Song -> Nested List
(define (make-cell data)
  `(td ,data))

; makes a row for the song table based on a list of values (eg ranking + title)
(define (make-row l)
  (cond ((empty? l) '())
        (else (cons (make-cell (first l))
                    (make-row (rest l))))))

; simple test on a single row. These tests are the same, I am just practising the new list notation.
(check-expect (make-row '(1 "A"))
              (list (list 'td 1) (list 'td "A") ))
(check-expect (make-row '(1 "A"))
              '((td 1) (td "A")))


; creates a list row for each song in the list
(define (make-rows los)
  (cond ((empty? los) empty)
        (else  `( (tr ,@(make-row (first los)))
                  ,@(make-rows (rest los))))))

; a short happy test. should split our short list into two rows
; I really struggled to get this function working before I wrote this test.
; Once I had the test, the function was simple.
(check-expect(make-rows (ranking short-list))
              '((tr (td 1) (td "A")) (tr (td 2) (td "B"))))

; creates a list based table structure
(define (make-table-list los)
  `(table ((border 1))
           ,@los))

; happy test - this should produce a complete table list
(check-expect (make-table-list (make-rows (ranking short-list)))
              '(table ((border 1))
                      (tr (td 1) (td "A"))
                      (tr (td 2) (td "B"))))
                     
; helper function that wraps the ranking and name into a table list from a list
(define (make-table-helper list)
  (make-table-list (make-rows (ranking list))))


When run, we get:


(make-table-helper one-list)

(list 'table (list (list 'border 1)) (list 'tr (list 'td 1) (list 'td "Asia: Heat of the Moment")) (list 'tr (list 'td 2) (list 'td "U2: One")) (list 'tr (list 'td 3) (list 'td "The White Stripes: Seven Nation Army")))

Wednesday, 14 November 2012

Exercise 184: Eliminate quasiquote, unquote, and unquote-splicing from the following expressions so that they are written with list instead


Eliminate quasiquote, unquote, and unquote-splicing from the following expressions so that they are written with list instead:

  • `(0 ,@'(1 2 3) 4)
  • this table-like shape:
    `(("alan" ,(* 2 500))
      ("barb" 2000)
      (,@'(list "carl" " , the great")   1500)
      ("dawn" 2300))
  • and this third web page:
    `(html
       (body
         (table ((border "1"))
           (tr ((width "200")) ,@(make-row '( 1  2)))
           (tr ((width "200")) ,@(make-row '(99 65))))))
    where make-row is the function from above.
Also write down the nested lists that the expressions produce.

Question One


`(0 ,@'(1 2 3) 4)

becomes

 (list 0 1 2 3 4)

This is very straight forward. The ` operator will start creating a list, the ,@'(1 2 3) will execute the ' creating (list 1 2 3) which will  will be spliced back into our main list.


Question Two

`(("alan" ,(* 2 500))  ("barb" 2000)  (,@'(list "carl" " , the great")   1500)  ("dawn" 2300))
This is what I thought the list would produce - I was wrong.
(list (list "alan" 1000)      (list "barb" 2000)      (list "carl the great" 1500)      ("dawn" 2300))

What it actually produced was:
(list (list "alan" 1000)      (list "barb" 2000)      (list 'list "carl" " , the great" 1500)      (list "dawn" 2300))

I'm not sure if this was meant to be a trick question, but it got me =)
With the answer in front of me, I now interpret the line  (,@'(list "carl" " , the great")   1500) as (list "carl" ", the great) as create a list containing the symbol 'list, the word "carl" and ", the great") and splice this list back into the result.

Nest listed Representation - I'm not 100% sure about this - I think the representation for carl the great is wrong:
'((alan 1000)  (barb 2000)  ('(carl (the great)) 1500)  (dawn 2300))

Question Three

`(html   (body     (table ((border "1"))       (tr ((width "200")) ,@(make-row '( 1  2)))       (tr ((width "200")) ,@(make-row '(99 65))))))


My first cut - this was pretty much 100% wrong.
(list "html"      (list "body"            (list "table"                  (list "border 1")                  (list "tr"                        (list "width" "200")                        (list (list "td" 1) (list "td" 2))))                  (list "tr"                        (list "width" "200")                        (list (list "td" 99) (list "td" 65)))))    

This is the actual answer as given by racket. I've forgotten to use symbols completely, and messed up the double list wrapping for the border styles.
(list 'html      (list 'body            (list 'table                  (list (list 'border "1"))                  (list 'tr (list (list 'width "200"))                        (list 'td "1") (list 'td "2"))                  (list 'tr (list (list 'width "200"))                        (list 'td "99") (list 'td "65")))))

Nested List Representation:
'(html  (body   (table (border "1")          (tr (width "200")              (td 1) (td 2))          (tr (width "200")              (td 99) (td 65)))))