Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
(check-expect (listify empty) empty)
(check-error (listify '(a))  "listify: no open token found!")
(check-expect (listify (list (make-open) (make-close))) (list empty))
(check-expect (listify (list (make-open) 'a (make-close))) (list '(a)))
(check-expect (listify (list (make-open) 'a 'b (make-close))) (list '(a b)))
(check-expect (listify (list (make-open) (make-open) 'a (make-close) 'b (make-close))) (list '((a) b))) 


Note the error style that is used:  the error message starts with the name of the function where the error occurred.   This is VERY useful when you have many functions that are calling each other and you have to figure out where an error occurred!

Methodology:

  1. Always start with the structural function template for the data structure that you are processing -- your code must fundamentally match the data you are working on.
    1. In this case, with generative recursion, we can modify our standard function template on a list, wtih the notion that the list of tokens has 4 possibilities: empty, open, close and everything else.   Create a template based on that "virtual" structural breakdown of the data.
    2. Are all the cases valid here?  For instance, can a valid list of tokens start with a "close"?    Write your listify function in terms of what is legal and what is not, leaving "..." where the list is legal.  We'll come back and fill that part in. 
  2. Next, consider how else the data breaks down.   Once again, in this generative recursion example, we can think of how the list of tokens breaks down into "phrases" that begin with "open" and end with "close".  
    1. The processing the list of tokens thus breaks down into processing a phrase, which ends with a "close" and the rest of the list of tokens, which is the rest of the token list after the matching "close" that ends the phrase.
    2. Write helper functions (let's call them "listify-phrase" and "listify-rest" for consistency's sake) to process these pieces of the token list.
  3. Write listify in terms of these helper function -- don't worry yet about how they work, just assume that they do  (maybe you should write their contract and purposes now?).  
    1. Since we've broken the problem down in terms of these two pieces, the "phrase" and the "rest of the tokens", the job now is to combine those results.
  4. Now write the helpers. 
    1. listify-rest:    Once again, break the function down into cases corresponding to the possible token types. 
      1. This function must find the matching "close" and return the list after that point.
      2. Are there illegal tokens you could encounter?
      3. What happens if you encounter an "open"?
    2. listify-phrase:   Once again, break the function down into cases corresponding to the possible token types.
      1. This must create a gen-list and assumes that the last token it needs to process is a "close".
      2. Are there illegal tokens you could encounter?
      3. What should you return if you encounter a "close"?
      4. What should you do if your encounter an "open"?
      5. What about something else, e.g. a symbol, number, whatever?   What about an empty list?

...

Code Block
(check-error (listify-rest empty) "listify-rest: encountered empty list!")
(check-expect (listify-rest (list (make-close))) empty)
(check-expect (listify-rest (list 1 (make-close))) empty)
(check-expect (listify-rest (list 1 (make-close) 2)) '(2))
(check-expect (listify-rest (list 1 (make-open) 2 3 (make-close) 4 (make-close) 5 6)) '(5 6))

(check-error (listify-phrase empty)  "listify-phrase: empty list encountered!")
(check-error (listify-phrase (list (make-open) (make-close)))  "listify-phrase: empty list encountered!")
(check-expect (listify-phrase (list (make-open) (make-close) (make-close))) '(()))
(check-error (listify-phrase (list (make-open) 'a (make-close))) "listify-phrase: empty list encountered!")
(check-expect (listify-phrase (list (make-open) 'a 'b (make-close) (make-close))) '((a b)))
(check-expect (listify-phrase (list 'x (make-open) 'a 'b (make-close) 'y (make-close))) '(x (a b) y))
(check-expect (listify-phrase (list 'x (make-open) (make-open) 'a (make-close) 'b (make-close) 'y (make-close))) '(x ((a) b) y)) 

...

You might find it useful to define the following predicate, though it is possible to not need it:

...