Upload
dannon
View
35
Download
0
Embed Size (px)
DESCRIPTION
PPL. Pairs, lists and data abstraction. Data Abstraction?. An interface: separate implementation from usage Think of the Map interface in Java: we know how to use it, but we don’t know how it’s implemented . Motivation: better software design, modularity, less maintenance and more!. - PowerPoint PPT Presentation
Citation preview
PPL
Pairs, lists and data abstraction
Data Abstraction?
• An interface: separate implementation from usage
• Think of the Map interface in Java: we know how to use it, but we don’t know how it’s implemented.
• Motivation: better software design, modularity, less maintenance and more!
Data Abstractions in Scheme?
• Of course, but first we need to present 2 new data types in Scheme:– Pairs– Lists
Pairs
• Combines two data entities into a single unit• Scheme provides built in primitives:– Value constructor: cons– Selectors: car, cdr– Identify predicate: pair?– Equality: equal?
Pairs
> (define x (cons 1 2))> (car x)1> (cdr x)2> x(1 . 2)
“toString” of pair
Pairs
Each data entity can be anything!> (define y (cons x (quote a)))> (car y)(1 . 2)> (cdr y)'a> y((1 . 2) . a)
Recall that x is the pair (cons 1 2)
Pairs
Do not confuse (cons 1 2) with (1 . 2) !!
1st is a Scheme expression (syntax) and 2nd is the ‘toString’ of the value
Pairs
Type constructor: PAIR
[T1*T2 -> PAIR(T1,T2)](λ (x y) (cons x y))
Recursive Pairs(define rec-pairs (λ (n) (if (= n 1) 1 (cons n (rec-pairs (- n 1))))))
> (rec-pairs 5)(5 4 3 2 . 1)
;(cons 5 (cons 4 (cons 3 (cons 2 (cons 1)))))
Recursive Pairs
We can also represent binary trees!(cons (cons 1 2) (cons (cons 3 4) (cons 5 6)))
((1 . 2) (3 . 4) 5 . 6)
Recursive Pairs• We have trees! How about searching a tree?(define member ? (lambda (el pair) (cond ((and (pair? (car pair)) (member? el (car pair))) #t) ((eq? el (car pair)) #t) ((and (pair? (cdr pair)) (member? el (cdr pair))) #t) ((eq? el (cdr pair)) #t) (else #f))))
Recursive Pairs
• How about counting number of leaves?(define count-leaves (λ (t) (if (not (pair? t)) 1 (+ (count-leaves (car t)) (count-leaves (cdr t))))))
Visual Representation
Lists
• Finite sequence <v1, …, vn> (v1 … vn)
• v1 is head, (v2 … vn) is tail• Value constructors: cons and list– Empty: (list)– Non-empty:• (cons head tail) – tail must be a list!• (list e1 … en)
Lists• Both will create the same list:(list 1 2 3)
(cons 1 (cons 2 (cons 3 (list))))
Lists
• Selectors:– car: head– cdr: tail
• Predicates:– list?– null?– equal?
Visual Representation
Lists and Types
• Homogenous– Examples: (1 2 3), ((1 2) (3)) – LIST(Number), LIST(T), …
• Heterogeneous– Examples: (1 #f 3), ((1 2) 3)– LIST
Useful List Operations
car + cdr:> (define x
(list 5 6 8 2))
> (car x)5> (cdr x)(6 8 2)
> (car (cdr x))6> (cadr x)6> (cddr x)(8 2)
Selector: list-ref
nth element of a list:(define list-ref (λ (l n) (if (= n 0) (car l) (list-ref (cdr l) (- n 1)))))
(define squares (list 1 4 9 16 25 36))
(list-ref squares 4)
Operator: length(define length (λ (l) (if (null? l) 0 (+ 1 (length (cdr l))))))
(define squares (list 1 4 9 16 25 36))
(length squares)6
Iterative length(define length (λ (l) (letrec ((iter (λ (l c) (if (null? l) c (iter (cdr l) (+ c 1)))))) (iter l 0))))
Operator: append
(define append (λ (l1 l2) (if (null? l1) l2 (cons (car l1) (append (cdr l1) l2)))))
(append (list 1 2 3) (list 3 4))
Iterative append ;; Type: [LIST * LIST -> LIST](define append (λ (l1 l2) (letrec ((iter (λ (l1 l2 c) (if (null? l1) (c l2) (iter (cdr l1) l2 (λ (app-cdr-l1) (c (cons (car l1) app-cdr-l1)))))))) (iter l1 l2 (lambda (x) x)))))
Constructor make-list
Builds a list of given with given values(define make-list (λ (l v) (if (= l 0) (list) (cons v (make-list (- l 1) v)))))
Using Lists to Represent Trees
• Very much like pairs, but better:– Empty tree ()– Leaf is just value– Non-empty tree – non-empty list
• Example: (1 (2 3)) is the tree:
Using Lists to Represent Trees
• How can we add data to non-leaf nodes? (i.e. labeled tree) : each node is also a list!
• ((1) ((2) (3)))• Now we can create labled trees:• (1 (0) (3 (2) (4)))
Leaves Count
• Unlabeled tree(define count-leaves (λ (t) (cond ((null? t) 0) ((not (list? t)) 1) (else (+ (count-leaves (car t)) (count-leaves (cdr t)))))))
Type Correctness with Pairs and Lists
• cons and list are primitives (not special forms!)
• So we need more axioms.
Pairs
For every type environment _Tenv and type expressions _S,_S1,_S2:Tenv |- cons:[S1*S2 -> PAIR(S1,S2)]Tenv |- car:[PAIR(S1,S2) -> S1]Tenv |- cdr:[PAIR(S1,S2) -> S2]Tenv |- pair?:[S -> Boolean]Tenv |- equal?:[PAIR(S1,S2)*PAIR(S3,S4) -> Boolean]
Homogenous ListsFor every type environment Tenv and type expression S:Tenv |- list:[Empty -> LIST(S)]Tenv |- list:[S* ...*S -> LIST(S)] n >0Tenv |- cons:[S*LIST(S) -> LIST(S)]Tenv |- car:[LIST(S) -> S]Tenv |- cdr:[LIST(S) -> LIST(S)]Tenv |- null?:[LIST(S) -> Boolean]Tenv |- list?:[S -> Boolean]Tenv |- equal?:[LIST(S)*LIST(S) -> Boolean]
Heterogeneous Lists
For every type environment Tenv and type expression S:Tenv |- list:[Empty -> LIST]Tenv |- cons:[S*LIST -> LIST]Tenv |- car:[LIST -> S]Tenv |- cdr:[LIST -> LIST]Tenv |- null?:[LIST -> Boolean]Tenv |- list?:[S -> Boolean]Tenv |- equal?:[LIST*LIST -> Boolean]
What About Data Abstraction?
• An interface: separation between usage (client) and implementation (supplier)
• Supplier gives getters, setters and other operators, and client uses them.
• Order of development:1. Client level2. Supplier level
ADT
• It’s a new type with a difference: type is semantic while ADT is syntactic
• Signature of constructor• Signature of operators• Invariants (see later)
So Why start with Pairs and Lists?
• Pairs and lists will be our implementation! The client will not know we used pairs and lists, she will just use the operations we give her!
• Example next slide
Binary Tree ADT: ConstructorsSignature: make-binary-tree(l,r)Purpose: Returns a binary tree whose left sub-
tree is l and whose right sub-tree is rType: [Binary-Tree*Binary-Tree -> Binary-Tree]Pre-condition: binary-tree?(l) and binary-
tree?(r)
Signature: make-leaf(d)Purpose: Returns a leaf binary-tree whose data
element is dType: [T -> Binary-Tree]
Binary Tree ADT: SelectorsSignature: left-tree(r), right-tree(r)Purpose: (left-tree <t>): Returns the left sub-tree
of the binary-tree <t>.(right-tree <t>): Returns the right sub-tree of the
binary-tree <t>.Type: [Binary-Tree -> Binary-Tree]Pre-condition: composite-binary-tree?(t)
Signature: leaf-data(r)Purpose: Returns the data element of the leaf binary-
tree <t>.Type: [Binary-Tree -> T]Pre-condition: leaf?(t)
Binary Tree ADT: PredicatesSignature: leaf?(t)Type: [T -> Boolean]Post-condition: true if t is a leaf -- constructed by make-leaf
Signature: composite-binary-tree?(t)Type: [T -> Boolean]Post-condition: true if t is a composite binary-tree --
constructed bymake-binary-tree
Signature: binary-tree?(t)Type: [T -> Boolean]Post-condition: result = (leaf?(t) or composite-binary-tree?(t) )
Signature: equal-binary-tree?(t1, t2)Type: [Binary-Tree*Binary-Tree -> Boolean]
Binary Tree ADT: Invariants
leaf-data(make-leaf(d)) = dleft-tree(make-binary-tree(l,r)) = lright-tree(make-binary-tree(l,r)) = rleaf?(make-leaf(d)) = trueleaf?(make-binary-tree(l,r)) = falsecomposite-binary-tree?(make-binary-tree(l,r)) = true
composite-binary-tree?(make-leaf(d)) = false
Binary Tree ADT: Client Level;Signature: count-leaves(tree);Purpose: Count the number of leaves of ’tree’;Type: [binary-Tree -> number](define count-leaves (lambda (tree) (if (composite-binary-tree? tree) (+ (count-leaves (left-tree tree)) (count-leaves (right-tree tree))) 1)))
Binary Tree ADT: Implementation;Signature: make-binary-
tree(l,r);Type: [(LIST union T1)*(LIST
union T2) ; -> LIST];Pre-condition: binary-tree?(l) ; and binary-tree?(r)(define make-binary-tree (lambda (l r) (list l r)))
;Signature: make-leaf(d);Type: [T -> T](define make-leaf (lambda (d) d))
;Signature: left-tree(t);Type: [LIST -> LIST union T];Pre-condition: composite-
binary-tree?(t)(define left-tree (lambda (t) (car t)))
;Signature: right-tree(t);Type: [LIST -> LIST union T];Pre-condition: composite-
binary-tree?(t)(define right-tree (lambda (t) (cadr t)))
Binary Tree ADT: Implementation;Signarture: leaf-data(t);Type: [T -> T];Pre-condition: leaf?(t)(define leaf-data (lambda (t) t))
;Signarture: leaf?(t);Type: [T -> Boolean](define leaf? (lambda (t) #t))
;Signarture: composite-binary-tree?(t);Type: [T -> Boolean](define composite-binary-tree? (lambda (t) (and (list? t) (list? (cdr t)) (null? (cddr t)) (binary-tree? (left-tree t)) (binary-tree? (right-tree t)))
Binary Tree ADT: Invariants
Seems ok, but look:> (leaf? (make-leaf (list 5 6)))#t> (has-leaf? (list 5 6) (make-leaf (list 5 6)))#f
We have no way to distinct composite leaves from tree…
We need a better implementation: tagged-data!
Tagged Data ADTSignature: attach-tag(x,tag)Purpose: Construct a tagged-data
valueType: [T*Symbol -> Tagged-
data(T)]
Signature: get-tag(tagged)Purpose: Select the tag from a
tagged-data valueType: [Tagged-data(T) -> Symbol]
Signature: get-content(tagged)Purpose: Select the data from a
tagged-data valueType: [Tagged-data(T) -> T]
Signature: tagged-data?(datum)
Purpose: Identify tagged-data values
Type: [T -> Boolean]
Signature: tagged-by? (tagged,tag)
Purpose: Identify tagged-data values
Type: [T*Symbol -> Boolean]
Binary Tree ADT: Implementation using Tagged-Data
;Signature: make-binary-tree(l,r);Type: [(LIST union T1)*(LIST
union T2) ; -> Tagged-data(LIST)];Pre-condition: binary-tree?(l) ; and binary-tree?(r)(define make-binary-tree (lambda (l r) (attach-tag (list l r) ’composite-binary-tree)))
;Signature: make-leaf(d);Type: [T -> Tagged-data(T)](define make-leaf (lambda (d) (attach-tag d ’leaf)))
;Signature: left-tree(t);Type: [Tagged-data(LIST) ; -> Tagged-data(LIST union
T)];Pre-condition: composite-binary-
tree?(t)(define left-tree (lambda (t) (car (get-content t))))
;Signature: right-tree(t);Type: [Tagged-data(LIST) ->
Tagged-data(LIST union T)];Pre-condition: composite-binary-
tree?(t)(define right-tree (lambda (t) (cadr (get-content t))))
Tagged-Data Implementation
• Have you noticed that we didn’t implement the tagged-data ADT?
• That’s the whole idea! We are clients! We don’t have to know the implementation!
• But we’ll give it anyway…
Tagged-Data ADT Implementation;Signature: attach-tag(x,tag);Type: [Symbol*T -> PAIR(Symbol, T)](define attach-tag (λ (x tag) (cons tag x)))
;Signature: get-tag(tagged);Type: PAIR(Symbol,T) -> Symbol(define get-tag (λ (tagged) (car tagged)))
;Signature: get-content(tagged);Type: [PAIR(Symbol,T) -> T](define get-content (λ (tagged) (cdr tagged)))
;Signature: tagged-data?(datum);Type: [T -> Boolean](define tagged-data? (λ (datum) (and (pair? datum) (symbol? (car datum)))))
;Signature: tagged-by?(tagged,tag);Type: [T*Symbol -> Boolean](define tagged-by? (λ (tagged tag) (and (tagged-data? tagged) (eq? (get-tag tagged) tag))))