![]() |
|
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 lon.
;; (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:
The base case defines the terminating situation for the structure or process. The inductive case defines how one can traverse the structure. |
How does this recursive definition relate to the structure of a list? See the UML diagram of a list in the last lecture.
Composites are recursive!
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)...(f-lon (rest a-lon))])) ;; INDUCTIVE CASE
ALL RECURSIVE ALGORITHMS CAN BE DECOMPOSED INTO A BASE CASE AND AN INDUCTIVE CASE.
Note that the f-lon in the inductive case does not necessarily have to be the same f-lon being defined!
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!
Don't use list when you should be using cons!!
©2003 Stephen Wong