Review; other possible data definitions

Okay, for review, finish off (by yourself) the examples from last time.
;; get-ingredients : list-of-nums-and-syms -> list-of-symbols
;; extracts a list of the symbols in the list
;;
(define (get-ingredients a-lons)
  (cond [(empty? a-lons) ..]
        [(symbol? (first a-lons)) ..(first a-lons)..
                                  ..(get-ingredients (rest a-lons)).. ]
        [(number? (first a-lons)) ..(first a-lons)..
                                  ..(get-ingredients (rest a-lons)).. ]))

;; substitute : list-of-nums-and-syms sym sym -> list-of-nums-and-syms
;; replaces all uses of the first symbols with the second symbol
;;
(define (substitute a-lons old-sym new-sym)
  (cond [(empty? a-lons) ..]
        [(symbol? (first a-lons)) ..(first a-lons)..
                                  ..(substitute (rest a-lons)).. ]
        [(number? (first a-lons)) ..(first a-lons)..
                                  ..(substitute (rest a-lons)).. ]))
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.

Data definition:
A list-of-nums-and-syms is one of
 - empty
 - (cons sym list-of-nums-and-syms) 
 - (cons num list-of-nums-and-syms)

Data definition:
A Recipe 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.

Note to prof: Here's a better? example of list-of-nums-and-syms.

Note: Is this the most appropriate definition for a recipe? What are some alternatives?
One possibility:

A stage is: A list of ingredients, and a cooking time.
A recipe is: a list of stages.
This is fine -- you'd have a template for list-of-stages, for stages, and for list-of-ingredients. But we'll stick with the list-of-nums-and-syms for now. Your representation should reflect how you think about the problem, but different people might think differently!

One other note about the details of list-of-nums-and-syms: It suffers the drawback that it doesn't separate the processing of the list, from the processing of an individual items. Compare:

; A Num-or-Sym is either:
;   - a num
;   - a symbol
;
; A List-of-Nums-and-Syms is either
;   - empty
;   - (cons Num-or-Sym List-of-Nums-and-Syms)


Some of you might be wondering, "hey, this self-referential definition of a list is confusing, and it isn't really needed." You probably want a definition along the lines of:
A list-of-numbers is:
Something that has a first number, then a second number, then a third number, ..., then a last number.
Well, as a definition, this has a couple of problems.


numbers au naturel

During the twelve days of christmas, we might be wondering how many items our true love gave us, on the nth day. Let's write a function which takes in a natural number n, and returns the sum of the first n numbers. (Sometimes called the nth triangular number -- think of arranging pennies on a table, into triangles.)

Hmmm, before writing code about natural numbers, let's be sure we're exactly clear on what the defintion of a natural number is. Well, ask any 7-year-old: it's 0, 1, 2, 3, ..., 29, 30, 31, .... But as a definition, this suffers from the ol' dot-dot-dot flaw: what explicitly is the pattern? Here's a hint (-:
0, (add1 0), (add1 (add1 0)), (add1 (add1 (add1 0))), ...
Admittedly, in everday life, we've given given shortened names to these things after 0, but mathematicians consider the natural number in this sense. (Some texts use "natural numbers" as starting from 1 and "whole numbers" as starting from 0; for our purposes, we'll consider zero as natural :-) Formally:

; A NatNum is:
;   - 0, or
;   - (add1 NatNum)
(Note: How do mathematicians prove things about all natural numbers? They use induction: prove something about 0, and then prove that add1 preserves the desired property; voila. Actually, when proving things about all lists, or all recipes, ... we generalize induction to structural induction. Take comp280 for details :-).

If add1 constructs new natNums, how do we tear apart a given non-zero natNum, to find the smaller natNum it's based on? Yes: sub1. (Of course, use (+ .. 1) and (- .. 1) if you prefer.)

What is the template for natural numbers?












Now (in a different color pen) go back and fill in the template, to get the code for (given n) computing the sum of the first n numbers: n + (n-1) + (n-2) ... + 2 + 1.

To think about: how many presents did our true love give us overall? (This is the sum of the first n triangular numbers, sometimes referred to as the nth pyramidal number -- think of arranging a pyramid of cannonballs.)

How about the product of the first n numbers (some times referred to as "n!").

;; (! n): natNum --> num
;; Given n, return n*(n-1)*...*2*1.
;;
(define (! n)
  (cond [(zero? n) ...]
        [else  ..(! (sub1 n))..]))

; Test cases
;
(! 2)
2

(! 3)
6

(! 0)
; ??? what should this be?
Think of attaching thought-bubbles to various parts of the code: Taking some concrete input (say, n = 23), What is (sub1 n)? How about (! (sub1 n))?

With a friend, quickly write the function

;; countdown: natNum --> list-of-natNum-or-symbol
;; Return a list of descending numbers, n .. 1, followed by 'blastoff!.







; Examples
(countdown 3)  = (cons 3 (cons 2 (cons 1 (cons 'blastoff! empty))))


; (other examples??)



At home: