There are two ways to define a list containing multiple forms of
information.  Let's consider two examples.

First, list-of-nums-and-syms.  Here are the two alternatives:

Definition 1:

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, or
 - (cons N lons)
     where N is a number and lons is a list-of-nums-and-syms.

Definition 2:

A list-of-nums-and-syms is either
 - empty, or
 - (cons NS lons)
     where NS is a num-or-sym and lons is a list-of-nums-and-syms.

A num-or-sym is either
 - a number, or
 - a symbol.

Second, a list of pizza toppings.  Here are the two alternatives:

Definition 1:

A list-of-toppings is one of
  - empty,
  - (cons 'cheese alot), where alot is a list-of-toppings,
  - (cons 'ham alot), where alot is a list-of-toppings, or
  - (cons 'onion alot), where alot is a list-of-toppings.

Definition 2:

A list-of-toppings is either
  - empty, or
  - (cons T alot), where T is a topping and alot is a
                    list-of-toppings.

A topping is one of
  - 'cheese,
  - 'ham, or
  - 'onion.

Which style is better, 1 or 2?  You will gain much more insight into
this question as you go on in computer science.  For now, here's a
general rule.  If there is a meaningful relationship between the
cases (as in the toppings example), use style 2.  Otherwise, you can
use style 1.  Note that in practice, the former case occurs far more
often than the latter.  You won't go wrong if you always use style 2.

Natural Numbers

Write a program gos which consumes a natural number n and returns a list
with n copies of 'go.

What's wrong here?  This isn't a simple function that computes one
number from another.  It's more complicated than that.  But for more
complicated programs, we usually start with a data definition.
Where's the data definition?

Let's write a data definition for the natural numbers.  When we wrote
the data definition for lists, we started with the smallest possible
list, empty.  What's the smallest natural number?  0.  How did we
build up lists?  We added one element onto an existing list.  Using
the same idea, how do we build up the natural numbers?  We add one to
an existing number.  This yields the following data definition:

A natural number is either
  - 0, or
  - (add1 n) where n is a natural number

Let's define some natural numbers using this definition:

0
(add1 0)
(add1 (add1 0))
(add1 (add1 (add1 0)))

Recall that in the case of lists, we have cons to build lists up and
first and rest to take lists apart.  We can build up natural numbers
using add1.  How do we take them apart?  We use sub1.

Now that we have the data definition, let's write gos.

; gos : N -> list-of-symbols
; create a list with n copies of 'go
(define (gos n) ...)

What are some examples?

(gos 0) = empty
(gos 2) = (cons 'go (cons 'go empty))

What does the template look like?

(define (gos n) 
  (cond [(zero? n) ...]
        [else ... (gos (sub1 n)) ...]))

Here's the full function.

(define (gos n) 
  (cond [(zero? n) empty]
        [else (cons 'go (gos (sub1 n)))]))

Admittedly, this is a somewhat silly example.  Let's turn to something
more realistic.  Sometimes, we want to graph functions over the
natural numbers.  Let's write a program create-points that we could
use to graph the function f(x) = x * x.  What do we need?  A data
definition for points.

A point is a structure
  (make-point x y)
where x and y are numbers

;; create-points : N -> list-of-points
;; creates a list of points in which each y coordinate is the square
;; of the x coordinate
(define (create-points n)
  (cond [(zero? n) empty]
        [else (cons (make-point n (* n n))
                    (create-points (sub1 n)))]))

This program produces points for numbers in the range 0 to n.  What if
we wanted our program to only graph numbers larger than 10?  We need
to change the purpose statement and we need a new data definition.

A natural number [>= 10] is either
  - 10, or
  - (add1 n), where n is a natural number [>= 10]

How does the function above change?  Only in the contract and the base
case.

;; create-points : N [>= 10] -> list-of-points
;; creates a list of points in which each y coordinate is the square
;; of the x coordinate and each x coordinate is larger than 10.
(define (create-points n)
  (cond [(= n 10) empty]
        [else (cons (make-point n (* n n))
                    (create-points (sub1 n)))]))

What if we wanted to include the point with x-coordinate 10?  How do
we change the above function?

;; create-points : N [>= 10] -> list-of-points
;; creates a list of points in which each y coordinate is the square
;; of the x coordinate and each x coordinate is larger than 10.
(define (create-points n)
  (cond [(= n 10) (cons (make-point n (* n n)) empty)]
        [else (cons (make-point n (* n n))
                    (create-points (sub1 n)))]))

Why don't we just change (= n 10) to (< n 10)?  Because that would
violate the data definition.

Finally, let's develop a program multiply, which consumes a natural
number n and a number m and produces n * m, but without using
multiplication. 

;; multiply : N num -> num
;; multiplies a natural number by a num without using *
(define (multiply n m)
  (cond [(zero? n) 0]
        [else (+ m (multiply (sub1 n) m))]))