Tuesday, 13 March 2012

Exercise 157b: On some occasions lists are formed with cons and list. Reformulate the following lists using list exclusively


Exercise 157: On some occasions lists are formed with cons and list. Reformulate the following lists using list exclusively:;


;(cons "a" (list 0 false))
;
;(list (cons 1 (cons 13 empty)))
;
;(cons (list 1 (list 13 empty)) empty)
;
;(list empty empty (cons 1 empty))
;
;(cons "a" (cons (list 1) (list false empty)))

Whoops! Completely missed that second part about doing this also exclusively using list. Luckily this is a lot easier than doing them using cons exclusively. The tricky part about this exercise was doing it all in your head before pasting the source expression into racket - as soon as you do that, racket gives the answer formatted using list. Doh!



;1 Reformulate: (cons "a" (list 0 false))
(check-expect (cons "a" (list 0 false))
              (list "a" 0 false))


  
;2 Reformulate (list (cons 1 (cons 13 empty)))
(check-expect (list (cons 1 (cons 13 empty)))  
              (list (list 1 13) ))
              
;3 Reformulate (cons (list 1 (list 13 empty)) empty)
(check-expect (cons (list 1 (list 13 empty)) empty)
              (list (list 1 (list 13 empty))))


;4 Reformulate
;(list empty empty (cons 1 empty))
(check-expect (list empty empty (cons 1 empty))
              (list empty empty (list 1)))




;5 Reformulate (cons "a" (cons (list 1) (list false empty)))
(check-expect (cons "a" (cons (list 1) (list false empty)))
              (list "a" (list 1) false empty))

Tuesday, 6 March 2012

Exercise 157: On some occasions lists are formed with cons and list. Reformulate the following lists using cons and empty exclusively


Exercise 157: On some occasions lists are formed with cons and list. Reformulate the following lists using cons and empty exclusively



;(cons "a" (list 0 false))
;
;(list (cons 1 (cons 13 empty)))
;
;(cons (list 1 (list 13 empty)) empty)
;
;(list empty empty (cons 1 empty))
;
;(cons "a" (cons (list 1) (list false empty)))


This exercise was pretty straight forward. I just built up the lists from scratch only using cons.

;1 Reformulate: (cons "a" (list 0 false))
(check-expect (cons "a" (cons 0 (cons false empty)))
              (cons "a" (list 0 false)))




;2 Reformulate: (list (cons 1 (cons 13 empty)))
(check-expect (list (cons 1 (cons 13 empty)))  
              (cons (cons 1 (cons 13 empty)) empty) )
    
          
;3 Reformulate (cons (list 1 (list 13 empty)) empty)
;  this one is a little more interesting - we are making 
;  a list of empty lists - easy enough to do though with 
;  a (cons empty empty)
(check-expect (cons (list 1 (list 13 empty)) empty)
              (cons (cons 1 (cons (cons 13 
                            (cons empty empty)) empty)) empty))


;4 Reformulate: (list empty empty (cons 1 empty))
(check-expect (list empty empty (cons 1 empty))
              (cons empty (cons empty (cons 
                                      (cons 1 empty) empty))))




;5 Reformulate: (cons "a" (cons (list 1) (list false empty)))
(check-expect (cons "a" (cons (list 1) (list false empty)))
              (list "a" (list 1) false empty))

Tuesday, 21 February 2012

Exercise 156: Use cons and empty to construct lists.


Exercise 156: Use cons and empty to construct the equivalent of the following lists:

; 1) (list 0 1 2 3 4 5)
; 2) (list (list "adam" 0) (list "eve" 1) (list "louisXIV" 2))
; 3) (list 1 (list 1 2) (list 1 2 3))

I found this exercise a little harder than expected. This is because I very quickly got tired of using cons to build up lists and have been using list most of the time.
It's good to have the theory and knowledge of lists being constructed of cons and empty, but in practise it is far too tedious.



1) This is very straight forward - just a list of cons...


(check-expect (cons 0 (cons 1 (cons 2 (cons 3 (cons 4 (cons 5 empty ))))))              
              (list 0 1 2 3 4 5))






2) This is a little more complex - each sublist needs to be cons back into the main list. 


(check-expect (cons (cons "adam" (cons 0 empty))
                    (cons (cons "eve"  (cons 1 empty))
                          (cons (cons "louisXIV" (cons 2 empty)) empty)))
              (list (list "adam" 0) (list "eve" 1) (list "louisXIV" 2)))






3) Again, a little more complex. I found it easier to build this up from the inside.


(check-expect (cons 1 
                    (cons (cons 1 (cons 2 empty)) 
                          (cons (cons 1 (cons 2 (cons 3 empty))) empty)))
              (list 1 (list 1 2) (list 1 2 3)))

Tuesday, 14 February 2012

Question 155: List Processing


Before we start . . . you may ask what happened to question 154? Well, there doesn't seem to be a question 154 in the book! There is an exercise there, but they give you the answer! So, on to question 155...

I had actually 'cheated' somewhat here, and given up on cons a long time ago. A quick hunt through the manual showed the list command and and I've been using that since right near the start.

This is very straight forward exercise:


; Question 1
(check-expect (list "a" "b" "c" "d" "e")
    (cons "a" 
          (cons "b" 
                (cons "c" 
                      (cons "d" 
                            (cons "e" empty))))))
; Question 2
(check-expect (list (list 1 2))
              (cons (cons 1 (cons 2 empty)) empty))


; Question 3
(check-expect (list "a" (list 1) false)
              (cons "a" (cons (cons 1 empty) (cons false empty))))


; Question 4
(check-expect (list (list 1 2) (list 2))
              (cons (cons 1 (cons 2 empty)) (cons (cons 2 empty) empty)))


; Question 5
(check-expect (list (list "a" 2) "hello")
              (cons (cons "a" (cons 2 empty)) (cons "hello" empty))eB.


; Question 1
(check-expect (list "a" "b" "c" "d" "e")
    (cons "a" 
          (cons "b" 
                (cons "c" 
                      (cons "d" 
                            (cons "e" empty))))))
; Question 2
(check-expect (list (list 1 2))
              (cons (cons 1 (cons 2 empty)) empty))


; Question 3
(check-expect (list "a" (list 1) false)
              (cons "a" (cons (cons 1 empty) (cons false empty))))


; Question 4
(check-expect (list (list 1 2) (list 2))
              (cons (cons 1 (cons 2 empty)) (cons (cons 2 empty) empty)))


; Question 5
(check-expect (list (list "a" 2) "hello")
              (cons (cons "a" (cons 2 empty)) (cons "hello" empty)))

Wednesday, 8 February 2012

Exercise 153: Yet More Text Editing

Note: This question is building on the answers to the questions preceding it. Rather than include the code from the last questions each time, I am only including that code which is specific to this question. If I seem to be missing a function or two, I suggest you go look at one of the previous answers!


 Exercise 153: Design the functions

;; Editor -> Editor
;; move the cursor position one 1String left, if possible
;(define (editor-lft ed)
;  ed)

;; Editor -> Editor
;; move the cursor position one 1String right, if possible
;(define (editor-rgt ed)
;  ed)

;; Editor -> Editor
;; delete one 1String to the left of the cursor, if possible
;(define (editor-del ed)
;  ed)


These are all fairly straight forward functions - simple list manipulation with no recursion to worry about. The challenge here lies in coming up with a reasonable test suite. 


; Editor -> Editor
; move the cursor position one 1String left, if possible
; All we need to do is remove the leading character of the
; 'pre' list and append it to the start of the 'post' list
(define (editor-lft ed)
  (cond ((empty? (editor-pre ed)) ed)
        (else (make-editor (rest (editor-pre ed)) 
                           (cons (first (editor-pre ed)) 
                                 (editor-post ed))))))


; simple case - text on both sides, should move cursor to
; the left
(check-expect (editor-lft (create-editor "eht" "word"))
              (create-editor "ht" "eword"))




; empty on left hand side - shouldn't change state
(check-expect (editor-lft (create-editor "" "word"))
              (create-editor "" "word"))


I can't think of any other test cases we need to cover here - if editor-post is populated or empty, it shouldn't make any difference to our functions.




; Editor -> Editor
; move the cursor position one 1String right, if possible
; This is the inverse of editor-lft - remove the first character
; from the 'post' text and prepend that to the 'pre' text
(define (editor-rgt ed)
  (cond ((empty? (editor-post ed)) ed)
        (else (make-editor (append   
                            (explode (first (editor-post ed))) 
                            (editor-pre ed) )
                           (rest (editor-post ed))))))


; simple case - text on both sides, should move cursor to the right
; Bear in mind that editor-pre is stored reversed, so we need to add chars to the front
; of it.
(check-expect (editor-rgt (create-editor "eht" "cat"))
              (create-editor "ceht" "at"))


; empty on right hand side - shouldn't change state
(check-expect (editor-rgt (create-editor  "word" ""))
              (create-editor  "word" ""))


; empty on both sides - shouldn't change state
(check-expect (editor-rgt (create-editor  "" ""))
              (create-editor  "" ""))



; Editor -> Editor
; delete one 1String to the left of the cursor, if possible
(define (editor-del ed)
    (cond ((empty? (editor-pre ed)) ed)
        (else (make-editor (rest (editor-pre ed)) 
                           ( editor-post ed)))))
  




; simple case - string populated on both sides should just
; delete the first chart to the left
(check-expect (editor-del (create-editor  "eht" "cat"))
              (create-editor  "ht" "cat"))


; if the editor-pre is not populated, then nothing should change
; (as there is nothing to delete)
(check-expect (editor-del (create-editor  "" "cat"))
              (create-editor  "" "cat"))


; if the editor-post is not populated, then should still
; be a straight forward delete
(check-expect (editor-del (create-editor  "eht " ""))
              (create-editor  "ht " ""))


; if the editor-post *and* editor-pre are not populated, 
; then nothing should happen
(check-expect (editor-del (create-editor  "" ""))
              (create-editor  "" ""))


; and finally, check what happens when there is exactly
; one character to delete
(check-expect (editor-del (create-editor  "a" "xxx"))
              (create-editor  "" "xxx"))

Sunday, 8 January 2012

Exercise 152: More text editing...


Note: These are my answers as I originally created them. As I have moved on to questions 153 and 154  I have discovered that some of my tests are simply wrong. I've left them incorrect here as this was how  I originally answered them and they aren't actually being as part of this answer. You will need to read the posts for questions 153 and 154 to see my (corrected) answers!!!

Explain why the template for editor-kh deals with "\t" and "\r"  before it checks for strings of length 1.

Strings of length 1 (ie, ordinary typed characters) need to be simply inserted into the text. ; Any special characters (eg tabs, backspaces) need to take an appropriate special action (eg deleting text, adding a carriage return etc).

The issue is that "\b", "\r" etc are only one charater long eg:

> (string-length "\b")
 1

 So, we need to check for and handle these special characters first, and only then handle any other ordinary single characters;



; code supplied by the text book
(define (editor-kh ed k)
  (cond
    [(key=? k "left") (editor-lft ed)]
    [(key=? k "right") (editor-rgt ed)]
    [(key=? k "\b") (editor-del ed)]
    [(key=? k "\t") ed]
    [(key=? k "\r") ed]
    [(= (string-length k) 1) (editor-ins ed k)]
    [else ed]))


; dummy functions
(define (editor-lft ed) 1)
(define (editor-rgt ed) 1)
(define (editor-del ed) 1)


(define (editor-ins ed k)
  (make-editor (cons k (editor-pre ed)) (editor-post ed)))



; test function for editor-ins. Empty editor should let you
; insert text at the front of the pre element
(check-expect
  (editor-ins (make-editor empty empty) "e")
  (make-editor (cons "e" empty) empty))


; test function for editor-ins. Text should be inserted before
; any existing text. Remember that the letters in 'pre' are
; stored in reverse order, so if we want to append text, 
; we need to append it to the start. 
; This apparently makes the design easier, but they
; haven't clarified why this should be ... (yet)
(check-expect
  (editor-ins (make-editor (cons "d" empty)
                           (cons "f" (cons "g" empty)))
              "e")
  (make-editor (cons "e" (cons "d" empty))
               (cons "f" (cons "g" empty))))


Anything below here is from 151.scm and is included cause we need these chunks of code - these aren't part of the answers to this question. Comments have been removed - if you're curious, go and read the post for question 151!

; Lo1s -> Lo1s
; produce a reverse version of the given list
 (check-expect
 (rev (cons "a" (cons "b" (cons "c" empty))))
  (cons "c" (cons "b" (cons "a" empty))))

(define (rev l)
  (cond ((empty? l) l)
        ((cons? l) (add-to-end (first l) 
                               (rev (rest l)))))) 


; adds an item to the end of the given list
; I didn't read this section of the manual as I wanted to come up 
; with this on my own. 
; I had issues at this point as I kept wanting to use 'cons' to join the two
; lists together - this of course results in a nested list (which is not what
; we want. eg;
; (cons (list "a" "b") (cons "a" empty)) => (list (list "a" "b") "a")
; After I discovered the 'append' function, this function shrank away to almost
; nothing. The only reason we need it now, is to save creating the second
; list with item and empty in the main function.
(define (add-to-end item l)
   (append l (cons item empty)
  ))


(check-expect (add-to-end "a" empty) (list "a"))
(check-expect (add-to-end "c" (list "a" "b")) (list "a" "b" "c"))






; An Editor is (make-editor Lo1S Lo1S)
; An Lo1S is one of:
; – empty
; – (cons 1String Lo1S)
(define-struct editor (pre post))


; This function consumes two strings and produces an Editor.
(define (create-editor left-string right-string)
  (make-editor (explode left-string) (explode right-string)))


; These values are given directly by the question 
; constants
(define HEIGHT 20) ; the height of the editor
(define WIDTH 200) ; its width
(define FTSZ 11) ; the font size
(define FTCL "black") ; the font color

; graphical constants - also supplied directly by the question
(define MT (empty-scene WIDTH HEIGHT))
(define CU (rectangle 1 HEIGHT "solid" "red"))


; Editor -> Image
; render an editor as an image of the two texts separated by the cursor
; (supplied directly from the question)
(define (editor-render e)
  MT)



; main : String -> Editor
; launch the editor given some initial string
; (supplied directly from the question)
(define (main s)
   (big-bang (create-editor s "")
             (on-key editor-kh)
             (to-draw editor-render)))


; At this point we can actually call our editor, but it doesn't
; do anything interesting yet. (Or anything at all really!)
;(make-editor (make-editor "Hello" "World") "")


; The first two test statements are supplied by the question.
; This first checks to make sure that when you press 'e' you
; create an editor displaying e
(check-expect (editor-kh (create-editor "" "") "e")
              (create-editor "e" ""))


; This checks that when you type 'e', it's added at the cursor point
; (rather than the beginning or end of the editor)
(check-expect (editor-kh (create-editor "cd" "fg") "e") 
              (create-editor "ecd" "fg"))




Monday, 7 November 2011

Exercise 151 - Designing an editor


Exercise 151: Design the function create-editor.

The function consumes two strings  and produces an Editor. The first string is the text to the left of the cursor and the second string is the text to the right of the cursor. The rest of the section relies on this function.

First up, I wanted to roll my own rev function instead of going off the one in the book. This was a fairly short question and so needed some padding to make it interesting!

; Lo1s -> Lo1s
; produce a reverse version of the given list

(check-expect
 (rev (cons "a" (cons "b" (cons "c" empty))))
  (cons "c" (cons "b" (cons "a" empty))))

(define (rev l)
  (cond ((empty? l) l)
        ((cons? l) (add-to-end (first l) 
                               (rev (rest l)))))) 


Now we need our wish-list function 'add-to-end'.
I didn't read this section of the manual as I wanted to come up  with the solution to this on my own.
I had issues at this point as I kept wanting to use 'cons' to join the two lists together - this of course results in a nested list (which is not what we want). eg;

(cons (list "a" "b") (cons "a" empty)) 
  => (list (list "a" "b") "a")


After I discovered the 'append' function, this function shrank away to almost nothing. The only reason we need it now, is to save creating the second list with item and empty in the main function.

; adds an item to the end of the given list
(define (add-to-end item l)
   (append l (cons item empty)
  ))


(check-expect (add-to-end "a" empty) (list "a"))
(check-expect (add-to-end "c" (list "a" "b")) 
              (list "a" "b" "c"))


Now, for the actual question - we need to make an Editor. This function consumes two strings and produces an Editor.

; An Editor is (make-editor Lo1S Lo1S)
; An Lo1S is one of:
; - empty
; - (cons 1String Lo1S)
(define-struct editor (pre post))

This method really seems overkill (or I'm not doing something I  should be doing... it seems we've cut down on typing by 2 characters (the difference between m-a-k-e and c-r-e-a-t-e)

Perhaps my possible lack of comprehension will become clearer later on in exercise 152, but for now, this is what I think they are after ...

(define (create-editor left-string right-string)
  (make-editor left-string right-string))


All these constants below are given by the question - I'm just pasting them here for completeness

; constants
(define HEIGHT 20) ; the height of the editor
(define WIDTH 200) ; its width
(define FTSZ 11) ; the font size
(define FTCL "black") ; the font color

; graphical constants - also supplied directly by the question
(define MT (empty-scene WIDTH HEIGHT))
(define CU (rectangle 1 HEIGHT "solid" "red"))


; Editor -> Image
; render an editor as an image of the two texts separated by the cursor
; (supplied directly from the question)
(define (editor-render e)
  MT)

; Editor KeyEvent -> Editor
; deal with a key event, given some editor
; (supplied directly from the question)
(define (editor-kh ed ke)
  ed)


; main : String -> Editor
; launch the editor given some initial string
; (supplied directly from the question)
(define (main s)
   (big-bang (create-editor s "")
             (on-key editor-kh)
             (to-draw editor-render)))

At this point we can actually call our editor, but it doesn't do anything interesting yet. (Or anything at all really!)

(make-editor (make-editor "Hello" "World") "")

The first two test statements are supplied by the question. The rest are what we need to come up to answer the question.

; This first checks to make sure that when you press 'e' you
; create an editor displaying e
(check-expect (editor-kh (create-editor "" "") "e")
              (create-editor "e" ""))


; This checks that when you type 'e', it's added at the 
; cursor point
; (rather than the beginning or end of the editor)
(check-expect (editor-kh (create-editor "cd" "fgh") "e")
              (create-editor "cde" "fgh"))


; check that pushing backspace deletes text from the 
; correct location
(check-expect (editor-kh (create-editor "Bob" "Dylan") "\b")
              (create-editor "Bo" "Dylan"))


(check-expect (editor-kh (create-editor "" "") "\b")
              (create-editor "" ""))


; check we can use the cursor to move to the left
(check-expect (editor-kh (create-editor "Bob" "Dylan") "left")
              (create-editor "Bo" "bDylan"))


(check-expect (editor-kh (create-editor "" "Dylan") "left")
              (create-editor "" "Dylan"))


; check we can use the cursor to move to the right
(check-expect (editor-kh (create-editor "Bob" "Dylan") "right")
              (create-editor "BobD" "ylan"))


(check-expect (editor-kh (create-editor "Bob" "") "right")
              (create-editor "Bob" ""))