Skip to main content

Lab: Deep recursion

Held
Monday, 22 April 2019
Writeup due
Wednesday, 24 April 2019
Summary
We explore techniques for processing nested lists.

Patterns of deep recursion

Here’s the generalized tally procedure from the reading.

(define deep-tally
  (lambda (lst pred?)
    (cond
      [(null? lst)
       0]
      [(pred? (car lst))
       (+ 1 (deep-tally (cdr lst) pred?))]
      [(list? (car lst))
       (+ (deep-tally (car lst) pred?) (deep-tally (cdr lst) pred?))]
      [else
       (deep-tally (cdr lst) pred?)])))

Here’s a more general pattern for deep recursion.

(define DEEP-FUN
  (lambda (lst)
    (cond
      [(BASE-CASE-TEST? lst)
       (BASE-CASE-COMPUTATION lst)]
      [(list? (car lst))
       (COMBINE1 (DEEP-FUN (car lst)) (DEEP-FUN (cdr lst)))]
      [else
       (COMBINE2 (car lst) (DEEP-FUN (cdr lst)))])))

Preparation

a. Review the two patterns of deep recursion given above.

b. Go over the self checks from the reading.

Exercises

Exercise 1: Containment

Write a procedure, (deep-contains? lst val), that takes a nested list and a value as parameters, and determines whether the value appears in the list or any of its sublists (or sub-sublists or …).

You should use equal? to compare values.

> (deep-contains? '(a (b (c) d) ((e))) 'c)
#t
> (deep-contains? '(a (b (c) d) ((e))) 'x)
#f

Exercise 2: Selecting strings

Write a procedure, (select-strings lst), that uses the pattern of deep recursion to select all of the strings from a nested list and return them as a list.

> (select-strings '(("this") "is" "a" (((("somewhat")) "nested")) "list"))
'("this" "is" "a" "somewhat" "nested" "list")
> (select-strings '("a" 1 ("and" "a" 2 ("and" "a" 3))))
'("a" "and" "a" "and" "a")

Exercise 3: Generalized selection

Write a generalized version of select-strings, (deep-select lst pred?), that selects all the values from a nested list for which a predicate holds.

Exercise 4: Flattening lists

Write a procedure, (flatten lst), that takes a nested list as a parameter and returns a “flat” list (one with no sublists) that contains the same values in the same order.

> (flatten '(1 (2 3 (4 5 (6)) 7) 8 (9 10) 11))
'(1 2 3 4 5 6 7 8 9 10 11)

Exercise 5: Alphabetically first

Write a procedure, (deep-alphabetically-first lst), that takes a nonempety nested list of strings as a parameter and returns the alphabetically first string in that nested list. You should process the nested list directly, rather than, say, flattening it first.

> (deep-alphabetically-first '("simple"))
"simple"
> (deep-alphabetically-first '("not" ("quite" ("as") "simple")))
"as"
> (deep-alphabetically-first '(("is" (("this" ("any") ("more" ("complex")))))))
"any"

Note: You will need a somewhat different base case than we’ve used in the prior procedures.

Note: This procedure should accept strings that contain non-letters and order them using modified ASCII order as determined by string-ci<=?.

Hint: As in past “best of” procedures, you will find it helpful to write a helper procedure that takes two strings as inputs and returns whichever of the two strings is alphabetically first.

Exercise 6: Deep reverse

Write a procedure, (deep-reverse val), that takes any Scheme value as a parameter. If the parameter is a list, deep-reverse should reverse both that list and any sublists that it may have. If the parameter is not a list, deep-reverse should return the value.

> (deep-reverse 1)
1
> (deep-reverse '(1 2 3))
'(3 2 1)
> (deep-reverse '(1 (2 3 (4 5) 6) 7 (8 9) 10))
'(10 (9 8) 7 (6 (5 4) 3 2) 1)

Warning: You may need a very different pattern of recursion than we used in the procedures above.

For those with extra time

If you find yourself with extra time, you might try one or more of the following problems.

Extra 1: Containment, revisited

Rewrite deep-contains? using and and or, rather than cond or `if.

Extra 2: Tallying pairs

You may have noted that using (deep-tally lst pair?) does not compute quite the value you would have expected. Write a procedure, (deep-tally-pairs val), that counts all the pairs in a Scheme value that does not contain any vectors.

> (deep-tally-pairs '(1 2 3))
3
> (deep-tally-pairs '(1 (2 3)))
4
> (deep-tally-pairs '((1) (2) (3)))
6

Acknowledgements

This lab was newly written for spring 2019. Although some of the problems resemble questions students asked earlier in the semester, those students should not be blamed for the questions on this lab, which were planned.