```
Lists can contain more than one kind of data.  Consider as a simple
example a list containing both numbers and symbols.  The data
definition for such a list is as follows:

A list-of-nums-and-syms is one of
- empty
- (cons S lons)
where S is a symbol and lons is a list-of-nums-and-syms
- (cons N lons)
where N is a symbol and lons is a list-of-nums-and-syms

We could use such a list to represent a recipe.  Each symbol names an
ingredient and each number indicates how long to cook before adding
the next ingredient.

Example of data:
(cons 'garlic (cons 'cumin (cons 5 (cons 'beans (cons 10 empty)))))

What does the template for a program over list-of-nums-and-syms look
like?

(define (... a-lons ...)
(cond [(empty? a-lons) ...]
[(symbol? (first a-lons))
... (first a-lons) ... (rest a-lons) ... ]
[(number? (first a-lons))
... (first a-lons) ... (rest a-lons) ... ]))

Let's write several programs over list-of-nums-and-syms:

;; cook-time : lons -> num
;; sum up all the numbers in the list

(define (cook-time a-lons)
(cond [(empty? a-lons) 0]
[(symbol? (first a-lons))
(cook-time (rest a-lons))]
[(number? (first a-lons))
(+ (first a-lons) (cook-time (rest a-lons)))]))

;; ingredient-count : lons -> num
;; count how many symbols are in the list

(define (ingredient-count a-lons)
(cond [(empty? a-lons) 0]
[(symbol? (first a-lons))
(+ 1 (ingredient-count (rest a-lons)))]
[(number? (first a-lons))
(ingredient-count (rest a-lons))]))

;; no-cook-recipe? : lons -> bool
;; returns true if there are no numbers in the list

(define (no-cook-recipe? a-lons)
(cond [(empty? a-lons) true]
[(symbol? (first a-lons))
(no-cook-recipe? (rest a-lons))]
[(number? (first a-lons)) false]))

Notice how similar these programs are!  The structure of the data
determines a large portion of the program.  By using the design
recipes, you can write large portions of your programs without
thinking about what the programs actually do.

;; get-ingredients : lons -> list-of-symbols
;; extracts a list of the symbols in the list

(define (get-ingredients a-lons)
(cond [(empty? a-lons) empty]
[(symbol? (first a-lons))
(cons (first a-lons) (get-ingredients (rest a-lons)))]
[(number? (first a-lons))
(get-ingredients (rest a-lons))]))

;; substitute : lons sym sym -> lons
;; replaces all uses of the first symbols with the second symbol

(define (substitute a-lons old-sym new-sym)
(cond [(empty? a-lons) empty]
[(symbol? (first a-lons))
(cond [(symbol=? (first a-lons) old-sym)
(cons new-sym (substitute (rest a-lons) old-sym new-sym))]
[else (cons (first a-lons)
(substitute (rest a-lons) old-sym new-sym))])]
[(number? (first a-lons))
(cons (first a-lons) (substitute (rest a-lons) old-sym new-sym))]))

These last two programs return lists, rather than atomic data such as
numbers and booleans.  Notice that they don't look much different from
the earlier programs.  Again, the template drives the definition of
the program.

```