The dream in a dream in a dream in a dream in a......
As we talked about before, lists are self-referential data structures, that is, they a structures that contain one of their own type. For instance, we could define a list of numbers as such:
;; A list-of-numbers "lon" is either
;; - empty
;; - cons, which has a first, which is a number,
;; and a rest, which is a list.
;; (cons num lon)
Since the definition of a lon includes a lon, we call this a "recursive definition".
Question: Isn't this a circular argument? How can we define anything in terms of itself? Is this definition really getting anywhere?
The answer is YES, it is a circular argument.....
Except that there are two parts to the definition (Gotcha!).
A recursive definition consists of at least 2 parts:
1) a base case that does not contain a reference to its own type.
2) an inductive case that does contain a reference to its own type.
The base case defines the terminating situation for the structure or process.
The inductive case defines how one can traverse the structure.
What does the recursive definition of a list imply about the template?
Nothing out of the ordinary actually:
(define (f-lon ...a-lon...)
(cond
[(empty? a-lon)...] ;; BASE CASE
[(cons? a-lon) ... (first a-lon)...(rest a-lon)])) ;; INDUCTIVE CASE
ALL RECURSIVE ALGORITHMS CAN BE DECOMPOSED INTO A BASE CASE AND AN INDUCTIVE CASE.
Variant: The specific behaviors of the base and inductive cases.
Invariant: The code used to glue the base and inductive cases together into a working function = template code.
;; sum: lon -> num
;; Sums the numbers in a lon.(define (sum a-lon)
(cond
[(empty? a-lon) 0]
[(cons? a-lon) (+ (first a-lon) (sum (rest a-lon)))]))"sum tests:"
(= 10 (sum l1))
(= 0 (sum empty))
(= 2 (sum l2))
Advice: You should know how to hand-evaluate a recursive function...hint, hint, nudge, nudge!
;; find_val: lon num -> boolean
;; Returns true if x is in a-lon
;; otherwise returns false(define (find_val a-lon x)
(cond
[(empty? a-lon) false]
[(cons? a-lon)(cond
[ (= x (first a-lon)) true] ;; This is a "terminal case"
[else (find_val (rest a-lon) x)])]))" find_val tests:"
(boolean=? false (find_val empty 42))
(boolean=? true (find_val l1 3))
(boolean=? false (find_val l2 3))
;;copy: lon -> lon
;; copies a lon(define (copy a-lon)
(cond
[(empty? a-lon) empty]
[(cons? a-lon) (cons (first a-lon) (copy (rest a-lon)))]))"copy tests:"
(equal? empty (copy empty))
(equal? l1 (copy l1))
(equal? l2 (copy l2))"Note, the following results in false:"
(eq? l1 (copy l1))
equals? compares the value of every element, including the values contained in any composed structures.
eq? simply checks if they are identically the same entity, i.e. the same piece of memory allocation.
The code for today, including the class exercises can be downloaded here.
Note: (list 1 2 3) is the same as (cons 1 (cons 2 (cons 3 empty)))
Warning!
(list 5 (list 3)) is not the same as (cons 5 (cons 3 empty)) !!!
(list 5 (list 3) is the same as (cons 5 (cons (cons 3 empty) empty)) -- the second element is a list, not a number!
©2002 Stephen Wong