<p>Hi Matthias, </p>
<p>Thanks for the feedback. Just a couple of questions before I give it another go if that's okay. I know there is something I need to learn from this exercise. </p>
<p>I am going through htdp first edition (at chapter 17 which refers to arrangements from chapter 12 which is why I revisited the exercise). Would you suggest continuing with this edition or moving to the draft second edition? </p>
<p>Do you mean the contract for insert-everywhere/word should be symbol word -> list of words? And will the words returned be the same length? Ie am I aiming for the same result as the current definition? </p>
<p>Thanks Sean. </p>
<div class="gmail_quote">On Jul 5, 2012 9:15 PM, "Matthias Felleisen" <<a href="mailto:matthias@ccs.neu.edu">matthias@ccs.neu.edu</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Sean,<br>
<br>
1. I have re-arranged your program so that it becomes readable:<br>
<br>
-- the function that explains it all comes first<br>
-- if you need a helper function, it is placed below<br>
-- don't place functions at top that are called by functions further down<br>
(roughly)<br>
<br>
-- make sure lines are at most 80 keystrokes wide<br>
<br>
2. I have separated the part you created with a == line from the one<br>
that is given.<br>
<br>
3. I added two comments in place where it becomes obvious that you<br>
didn't design according to the book but with an ad-hoc method.<br>
<br>
Overall, you discovered a design method that is introduced 2 chapters<br>
later. You used it when it is unnecessary to do so. The program is<br>
far more complicated (and thus slower) than needed.<br>
<br>
3a. It is possible that you have seen the exercise on creating a one-line<br>
editor (like Word or Notepad). At least the data structure suggests this<br>
is possible. IF SO (and I don't know whether this is true), then you might<br>
have designed by "copy example, change until it works". IF SO, let me<br>
strongly discourage this approach or -- if you do follow it -- let me<br>
encourage you to be aware of it and to attempt a systematic approach,<br>
which tends to produce much better results.<br>
<br>
4. PLEASE feel encouraged to try again. Read the first piece of<br>
in-lined comment to just skip the whole split-word data structure.<br>
Follow the design recipe and you will find a wonderful solution.<br>
<br>
-- Matthias<br>
<br>
<br>
<br>
<br>
#lang racket<br>
<br>
(require test-engine/racket-tests)<br>
<br>
;; Word -> [Listof Word]<br>
(check-expect (arrangements '(a)) (list '(a)))<br>
(check-expect (arrangements '(a b)) (list '(a b) '(b a)))<br>
<br>
(define (arrangements a-word)<br>
(cond<br>
[(empty? a-word) (cons empty empty)]<br>
[else<br>
(insert-everywhere/in-all-words (first a-word) (arrangements (rest a-word)))]))<br>
<br>
;; =============================================================================<br>
<br>
; A split-word is a struct where left and right are list of words<br>
(define-struct split-word (left right))<br>
<br>
;; insert-everywhere/in-all-words symbol list-of-words -> list of words<br>
;; insert the symbol in all possible positions in each word returning an<br>
;; expanded list of words<br>
<br>
(check-expect (insert-everywhere/in-all-words 'a (cons '(b) empty))<br>
(list (list 'a 'b) (list 'b 'a)))<br>
<br>
(check-expect (insert-everywhere/in-all-words 'd '((e r) (r e)))<br>
'((d e r) (e d r) (e r d) (d r e) (r d e) (r e d)))<br>
<br>
(define (insert-everywhere/in-all-words s a-low)<br>
(cond<br>
[(empty? a-low) empty]<br>
;; MF: this is where it gets weird (from what you know):<br>
;; why do you introduce an intermediate data structure (split-word)<br>
;; to represent a word? It is *difficult* to justify this design with<br>
;; the material in the first three chapters.<br>
;; the function insert-everywhere/word should really just consume a word<br>
[else (append (insert-everywhere/word s (make-split-word '() (first a-low)))<br>
(insert-everywhere/in-all-words s (rest a-low)))]))<br>
<br>
;;insert-everywhere/in-one-word symbol split-word -> low<br>
;; take a symbol and a split word and insert the symbol before and after each<br>
;; letter in the right hand side of the split creating a list of new words with<br>
;; the symbol progressing through.<br>
<br>
(check-expect (insert-everywhere/word 'a (make-split-word empty empty))<br>
(list (list 'a)))<br>
(check-expect (insert-everywhere/word 'a (make-split-word '(b) empty))<br>
(list '(b a)))<br>
(check-expect (insert-everywhere/word 'a (make-split-word empty '(b)))<br>
(list '(a b) '(b a)))<br>
(check-expect (insert-everywhere/word 'a (make-split-word empty '(b c)))<br>
(list '(a b c) '(b a c) '(b c a)))<br>
<br>
(define (insert-everywhere/word s a-sw)<br>
(cond<br>
[(empty? (split-word-right a-sw)) (cons (insert-symbol s a-sw) empty)]<br>
[else (cons (insert-symbol s a-sw)<br>
;; MF: this is where you go beyond what the design ideas you<br>
;; have seen in chapters 1 thru 3, and it makes the design<br>
;; utterly inelegant. Specifically, you are NOT applying<br>
;; insert-everywhere/word to a *piece* of a-sw but to a complete<br>
;; re-arrangement.<br>
(insert-everywhere/word s (move-split a-sw)))]))<br>
<br>
;; move-split split-word -> split-word<br>
;; return a new split word with the list on the left having the first of<br>
;; the right list appended to the end and the rest of the right<br>
(define (move-split a-sw)<br>
(cond<br>
[(empty? (split-word-right a-sw)) a-sw]<br>
[else (make-split-word<br>
(append (split-word-left a-sw) (list (first (split-word-right a-sw))))<br>
(rest (split-word-right a-sw)))]))<br>
<br>
(check-expect (move-split (make-split-word empty empty))<br>
(make-split-word empty empty))<br>
(check-expect (move-split (make-split-word '(a) empty))<br>
(make-split-word '(a) empty))<br>
(check-expect (move-split (make-split-word '(a) '(b)))<br>
(make-split-word '(a b) empty))<br>
(check-expect (move-split (make-split-word '(a) '(b c)))<br>
(make-split-word '(a b) '(c)))<br>
(check-expect (move-split (make-split-word '(a b) '(c d)))<br>
(make-split-word '(a b c) '(d)))<br>
<br>
;; insert-symbol symbol split-word -> word<br>
;; Insert the sysmbo at the front of the left list and append the right if left is empty<br>
;; Append to end of left if right list is empty<br>
;; Otherrwise insert between - returning one list<br>
<br>
(check-expect (insert-symbol 'a (make-split-word empty empty))<br>
'(a))<br>
(check-expect (insert-symbol 'a (make-split-word '(b) empty))<br>
'(b a))<br>
(check-expect (insert-symbol 'a (make-split-word empty '(b)))<br>
'(a b))<br>
(check-expect (insert-symbol 'a (make-split-word '(b) '(c)))<br>
'(b a c))<br>
<br>
(define (insert-symbol s a-sw)<br>
(cond<br>
[(empty? (split-word-right a-sw)) (append (split-word-left a-sw) (cons s empty))]<br>
[(empty? (split-word-left a-sw)) (cons s (split-word-right a-sw))]<br>
[else (append (split-word-left a-sw) (cons s (split-word-right a-sw)))]))<br>
<br>
</blockquote></div>