CS 227 Lecture -*-Outline -*-
focus: recursion over different kinds of types, and their relation to
recursion the recursive definition of those types.
* List representation of Trees (4.4)
The book calls this "Tree rep of lists" but that is backwards
This is a summary of the previous section (tree or deep recursion)
First will explain why we call lists with sublists trees
** how lists lists represent trees
in computer science we draw trees upside down (root system)
*** examples
these are trees of symbols
-------------------------
TREES REPESENTED BY LISTS
(a b c)
a b c
-------------------------
-------------------------
((a b) (() d))
(a b) (() d)
a b () d
------------------------
-------------------------
(a (b c d) ((e ()) g))
a (b c d) ((e ()) g)
b c d (e ()) g
e ()
------------------------
------------------------
()
-------------------------
*** terminology
point out on pictures too
def: the *nodes* of a tree are the whole list and each item,
top-level and nested, in the list
def: the *root* of a tree is the item at nesting level 0
def: a *branch* connects a list's node to the node for each of
its top-level items
def: a (proper) *subtree* is a tree nested inside another tree
def: a *leaf* in a (tree T) is a node that is a T
e.g., in a tree of atomic-items, () is not a leaf
but in a (tree atom), () is a leaf
def: the *depth* of a tree is the maximum nesting level of its leaves
*** abstract view of trees and implementation
-------------
TREE VALUES
Def: let T be a type of values.
A (tree T) is
either ()
or (x t1 t2 ...)
or (t1 t2 ...)
where x has type T
and t1, t2 ... have type (tree T)
-------------
this is the external representation too
-------------
TREE OBJECTS
REPRESENTATION VIEW:
Def: let T be a type of object.
A (tree T) object is
either '()
or (cons x t)
or (cons t1 t2)
where x has type T
and t1, t2 have type (tree T)
AS AN ABSTRACT DATA TYPE:
Def: let T be a type of object.
A (tree T) object is
either the-empty-tree
or (tree-cons x t)
or (tree-cons t1 t2)
where x has type T
and t1, t2 have type (tree T)
-------------
the book (and us in 4.3) took the representation view
we will consider the abstract view as a way of explaining trees better
*** basic procedures for trees
------------
BASIC PROCEDURES for TREES
the-empty-tree: (tree T)
tree-cons: (-> ((or T (tree T)) (tree T))
(tree T))
tree-empty?: (-> ((tree T)) boolean)
tree-first: (-> ((tree T))
(or T (tree T)))
; REQUIRES: the tree is not empty
tree-rest: (-> ((tree T)) (tree T))
; REQUIRES: the tree is not empty
(define the-empty-tree '())
(define tree-cons cons)
(define tree-empty? null?)
(define tree-first car)
(define tree-rest cdr)
------------
*** use in programming
**** sum-all expressed with tree operations
--------------
(define sum-all
; TYPE: (-> ((tree number)) number)
(lambda (ton)
; ENSURES: result is the sum of
; all the numbers in ton
(cond
((tree-empty? ton) 0)
((number? (tree-first ton))
(+ (tree-first ton)
(sum-all (tree-rest ton))))
(else (+ (sum-all (tree-first ton))
(sum-all (tree-rest ton))))
)))
--------------
**** tdepth
--------------
(tdepth '()) ==> 0
(tdepth '(a)) ==> 1
(tdepth '(a (b ((c))))) ==> 4
(tdepth '((e f) g)) ==> 2
(tdepth '((e () (f)))) ==> 3
(tdepth '(() (e () (f)))) ==> 3
tdepth: (-> ((tree atomic-item)) number)
--------------
base case, return 0
flat case: tree-first of tree is an atomic-item
have to get (tdepth tree) from
(tdepth (tree-first tree)) = 1
(tdepth (tree-rest tree))
e.g. if tree is (a (b ((c)))) have to get 4 from
(tdepth (tree-first tree)) = 1
and (tdepth (tree-rest tree))
= (tdepth '((b ((c))))) = 4
so looks like could take (tdepth (tree-rest tree))
but if tree is (a) thn have to get 1 from
(tdepth (tree-first tree)) = 1
and (tdepth (tree-rest tree)) = (tdepth '()) = 0
so (tdepth (tree-rest tree)) doesn't work.
By more examples or definition (involves maximum)
can see that the code is:
(max 1 (tdepth (tree-rest tree)))
tree case: tree-first of tree is a subtree
have to get (tdepth tree) from
(tdepth (tree-first tree))
(tdepth (tree-rest tree))
e.g. if tree is ((e () (f))) have to get 2 from
(tdepth (tree-first tree)) = (tdepth '(e () (f))) = 2
(tdepth (tree-rest tree)) = (tdepth '()) = 0
so looks like can use (add1 (tdepth (tree-first tree)))
but consideration of examples like
(tdepth '(() (e () (f)))) ==> 3
in which (add1 (tdepth (tree-first tree))) = 1
but (tdepth (tree-rest tree))
(tdepth '((e () (f)))) = 3
show that have to take the max of these
Another way to see this is by the definition and the fact
that the tree-first is nested nested but the tree-rest is not,
so code is:
(max (add1 (tdepth (tree-first tree)))
(tdepth (tree-rest tree)))
-------------
(DEFINE tdepth
; TYPE: (-> ((tree atomic-item)) number)
(LAMBDA (tr)
(COND
[(tree-empty? tr) 0]
[(atomic-item? (tree-first tr))
(max 1 (tdepth (tree-rest tr)))]
[ELSE
(max
(add1 (tdepth (tree-first tr)))
(tdepth (tree-rest tr)))])))
-------------
show trace of this (load "tdepth-trace.ss")
show what happens if call it on a symbol (error)
**** remove-left-most
---------------
(remove-left-most 'b
'(a (b c) () (c (b a))))
==> (a (c) () (c (b a)))
(remove-left-most 'c
'(a (b c) () (c (b a))))
==> (a (b) () (c (b a)))
(remove-left-most 'a '()) ==> ()
remove-left-most:
(-> (atomic-item (tree atomic-item))
(tree atomic-item))
What is the base case?
the flat case?
the tree case?
Write it using basic procedures for trees
---------------
Have them do this in groups
base case: return '()
flat case: if tree-first is an atomic-item
if equal to item, return the rest of tree
otherwise, recurse on rest of tree
tree case: if first of tree is a pair or null?
have to recurse in first and rest,
but only want to remove item once
so depends on where it is: first or rest
use member-all? to test
(DEFINE remove-left-most
; TYPE: (-> ((atomic-item
; (tree atomic-item)))
; (tree atomic-item))
(LAMBDA (item tr)
(COND
[(tree-empty? tr) '()]
[(atomic-item? (tree-first tr))
(COND
[(equal? item (tree-first tr))
(tree-rest tr)]
[ELSE (tree-cons
(tree-first tr)
(remove-left-most
item
(tree-rest tr)))])]
[ELSE
(COND
[(member-all? item (tree-first tr))
(tree-cons (remove-left-most
item
(tree-first tr))
(tree-rest tr))]
[ELSE (tree-cons
(tree-first tr)
(remove-left-most
item
(tree-rest tr)))])])))
improve this on-line (simplify)
the one in the book works for all datums
so in tree case consider if equal to item, return the rest of tr
*** summary: relation of definiton of tree to standard form
---------------
SUMMARY OF TREE RECURSION
for
(tree atomic-item)
DEFINITION STANDARD FORM of proc
(tree (LAMBDA (tr)
atomic-item) (COND
either () [(tree-empty? tr) ...]
or (x t1) [(atomic-item?
(tree-first tr)) ...]
or (t1 t2) [ELSE ...]))
where x has type atomic-item
and t1, t2 have type (tree atomic-item)
---------------
now compare and generalize, taking away the tree abstraction
to get back to the form of last time and the book
---------------------
SUMMARY OF TREE RECURSION
for
(tree T)
(representation view)
DEFINITION STANDARD FORM of proc
(tree T) (LAMBDA (tr)
is (COND
either () [(null? tr) ...]
or (x t1) [(T? (car tr)) ...]
or (t1 t2) [ELSE ...]))
where x has type T
and t1, t2 have type (tree T)
and T?: (-> (datum) boolean)
is such that (T? x) = #t
----------------
** recursion over the type s-expression
----------------
S-EXPRESSIONS
examples:
()
a
1
(a b 1)
(a . 3)
(() (c) (e f () h))
Def: an s-expression is either
a
or (cons s1 s2)
where a has type atom,
and s1, s2 have type s-expression.
Theorem: x is an s-expression
if and only if x has type
(or atom
(pair s-expression s-expression)).
----------------
all scheme expressions have this structure: (+ 3 (* 5 7))
but this includes much more, such as doted pairs.
*** depth
the depth program in the book is more general than tdepth
it works on atoms as arguments
------------
depth: (-> (s-expression) number)
(depth 'a) ==> 0
------------
base case is whether the item is an atom (recall this includes '())
return 0
the recursion in the recursive case goes down both car and cdr
since will take car of the case when the car is an atom
in the base case
-----------
(DEFINE depth
; TYPE: (-> (s-expression) number)
(LAMBDA (item)
; ENSURES: result is the maximum depth
; of item
(COND
[(atom? item) 0]
[(pair? item)
(max (add1 (depth (car item)))
(depth (cdr item)))])))
-----------
*** summary for atom or tree recursion
---------------
SUMMARY OF S-EXPRESSION RECURISON
DEFINITION STANDARD FORM of proc
a s-expression (LAMBDA (item)
is either (COND
a [(atom? item) ...]
or (cons s1 s2) [(pair? item)...]))
where a has type atom
and s1, s2 have type s-expression
----------------
** comparison to other type (data-driven recursion)
----------------
SUMMARY OF RECURISON
for
the type (flat) (list T)
DEFINITION STANDARD FORM of proc
a (list T) (LAMBDA (ls)
is either: (COND
() [(null? ls) ...]
or (cons x l) [ELSE ...]))
where x has type T
and l has type (list T)
a (non-empty-list (LAMBDA (ls)
T) is either: (COND
(cons x '()) [(null? (cdr ls)) ...]
or (cons x l) [ELSE ...]))
where x has type T
and l has type a (non-empty-list T)
----------------
from this we can generalize to other recursively defined types
--------------
GENERALIZING TO ANOTHER TYPE
BASIC PROCEDURES FOR type N
z: N
s: (-> (N) N)
p: (-> (N) N)
z?: (-> (N) boolean)
(z? z) = #t
(z? (s n)) = #f
(p (s n)) = n
DEFINITION STANDARD FORM of proc
An N is either
z
or (s n)
where n is an N
------------
fill in the standard form!
we can program add to like append
-----------
add: (-> (N) N)
(add z n2) = n2
(add (s n) n2) = (s (add n n2))
--------------
(DEFINE add
(LAMBDA (n1 n2)
(COND
[(z? n1) n2]
[ELSE (s (add (p n1) n2))]
)))
this is flat recursion over N
Can think of N as the natural numbers!
p = sub1
s = add1
z = 0
z? = zero?