Download presentation
Presentation is loading. Please wait.
1
Chapter 4 Data and Behavior Abstraction
PPL Chapter 4 Data and Behavior Abstraction
2
Abstract Data Type (ADT)
An interface: separation between usage (client) and implementation (supplier) Supplier gives constructors and selectors (getters), and client uses them. Order of development: Client level Supplier level
3
ADT It’s a new type with a difference: type is semantic while ADT is syntactic Signature of constructor Signature of operators Rules of correctness (Invariants)
4
Binary Tree ADT: Constructors
Signature: make-binary-tree(l,r) Purpose: Returns a binary tree whose left sub-tree is l and whose right sub-tree is r Type: [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 d Type: [T -> Binary-Tree]
5
Binary Tree ADT: Selectors
Signature: 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)
6
Binary Tree ADT: Predicates
Signature: leaf?(t) Type: [T -> Boolean] Post-condition: true if t is a leaf -- constructed by make-leaf Signature: composite-binary-tree?(t) Post-condition: true if t is a composite binary-tree -- constructed by make-binary-tree Signature: binary-tree?(t) Post-condition: result = (leaf?(t) or composite-binary-tree?(t) ) Signature: equal-binary-tree?(t1, t2) Type: [Binary-Tree*Binary-Tree -> Boolean]
7
Binary Tree ADT: Invariants
leaf-data(make-leaf(d)) = d left-tree(make-binary-tree(l,r)) = l right-tree(make-binary-tree(l,r)) = r leaf?(make-leaf(d)) = true leaf?(make-binary-tree(l,r)) = false composite-binary-tree?(make-binary-tree(l,r)) = true composite-binary-tree?(make-leaf(d)) = false
8
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)))
9
Binary Tree ADT: Client Level
More examples in lecture notes. Look at them. Really, look at them.
10
Binary Tree ADT: Implementation (supplier)
;Signature: make-binary-tree(l,r) ;Type: [T1*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 -> T] ;Pre-condition: composite-binary-tree?(t) (define left-tree (lambda (t) (car t))) ;Signature: right-tree(t) (define right-tree (lambda (t) (cadr t)))
11
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)))
12
Binary Tree ADT: Implementation
;Signarture: binary-tree(t) ;Type: [T -> Boolean] (define binary-tree? (lambda (t) (or (leaf t) (composite-b-t t)))) ;Signature: equal-binary-tree?(t1,t2) ;Type: [T1*T2 -> Boolean] ;Pre-condition: binary-tree?(t1) and binary-tree?(t2) (define equal-binary-tree? (λ (t1 t2) (cond ((and (composite-binary-tree? t1) (composite-binary-tree? t2)) (and (equal-binary-tree? (left-tree t1) (left-tree t2)) (right-tree t1) (right-tree t2)))) ((and (leaf? t1) (leaf? t2)) (equal? (leaf-data t1) (leaf-data t2))) (else #f))))
13
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!
14
Tagged Data ADT Signature: attach-tag(x,tag) Purpose: Construct a tagged-data value Type: [T*Symbol -> Tagged-data(T)] Signature: get-tag(tagged) Purpose: Select the tag from a tagged-data value Type: [Tagged-data(T) -> Symbol] Signature: get-content(tagged) Purpose: Select the data from a tagged-data value Type: [Tagged-data(T) -> T] Signature: tagged-data?(datum) Purpose: Identify tagged-data values Type: [T -> Boolean] Signature: tagged-by? (tagged,tag) Type: [T*Symbol -> Boolean]
15
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)] (define right-tree (cadr (get-content t))))
16
Proving Invariants Invariant: leaf-data(make-leaf (d)) = d: For expression d, eval[(leaf-data (make-leaf d))] = eval[d] eval[(leaf-data (make-leaf d))] ==> eval[(leaf-data (attach-tag eval[d] ’leaf))] ==> eval[(get-content (attach-tag eval[d] ’leaf))] ==> eval[d]
17
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…
18
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 (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) (tagged-data? tagged) (eq? (get-tag tagged) tag))))
19
Procedures as Data So far we’ve seen only pairs and lists as compound data Procedures can be data too! And in more than one way What?! Procedures can be data?! Yes.
20
Pair ADT Suppose Scheme did not include the built-in Pair or List type
Define the ADT (cons’r, getters, etc) Implement it using procedures(!!)
21
Pair ADT: Cons’r, Getters, Predicates…
Signature: cons(x,y) Type: [T1*T2 -> PAIR(T1,T2)] Signature: car(p) Type: [PAIR(T1,T2) -> T1] Signature: cdr(p) Type: [PAIR(T1,T2) -> T2] Signature: pair?(p) Type: [T -> Boolean] Signature: equal-pair?(p1,p2) Type: [PAIR(T1,T2)*PAIR(T1,T2) -> Boolean]
22
Pair ADT: Invariants (car (cons x y)) = x (cdr (cons x y)) = y
23
Pair ADT Implementation I: Eager (also called message passing)
Not to confuse with applicative-eval! ;Signature: cons(x,y) ;Type: [T1*T2 -> [Symbol -> (T1 union T2)] (define cons (λ (x y) (λ (m) (cond [(eq? m 'car) x] [(eq? m 'cdr) y] [else (error "..." m) ])))) לשים לב שהחתימות של המימוש מגלמות את הטיפוסים האמיתיים.
24
Pair ADT Implementation I: Eager
;Signature: car(pair) ;Type: [[Symbol -> (T1 union T2)] -> T1] (define car (λ (pair) (pair ’car))) ;Signature: cdr(pair) ;Type: [[Symbol -> (T1 union T2)] -> T2] (define cdr (pair ’cdr)))
25
What Just Happened? A pair is a procedure that stores the information about the pair components The “magic”: The substitution: the values are “planted” in the procedure The returned value is a procedure that is not applied. car and cdr apply it.
26
applicative-eval[ (cons 1 2) ] ==>. <closure (m) (cond ((eq
applicative-eval[ (cons 1 2) ] ==>* <closure (m) (cond ((eq? m ’car) 1) ((eq? m ’cdr) 2) (else (error “…" m) ))>
27
applicative-eval[ (car (cons 1 2 )) ] ==> applicative-eval[ car ] ==> <closure (pair) (pair ’car)> applicative-eval[ (cons 1 2) ] ==>* <the cons closure> sub[pair, <cons closure>, (pair ’car) ] ==> (<cons closure> ’car) reduce: ( (lambda (m) (cond ((eq? m ’car) 1) ((eq? m ’cdr) 2) (else (error "Argument not ’car or ’cdr -- CONS" m) ))) ’car) ==>* applicative-eval, sub, reduce: (cond ((eq? ’car ’car) 1) ((eq? ’car ’cdr) 2) (else (error “…" ’car) )) ==> 1
28
Pair ADT Implementation II: Lazy
Eager ;Signature: cons(x,y) ;Type: [T1*T2 ; -> [ [T1*T2 -> T3] -> T3]] (define cons (lambda (x y) (lambda (sel) (sel x y)))) ;Signature: cons(x,y) ;Type: [T1*T2 -> [Symbol -> (T1 union T2)] (define cons (λ (x y) (λ (m) (cond ((eq? m 'car) x) ((eq? m 'cdr) y) (else (error "..." m))))))
29
Pair ADT Implementation II: Lazy
;Signature: cons(x,y) ;Type: [T1*T2 -> [ [T1*T2 ; -> T3] -> T3]] (define cons (lambda (x y) (lambda (sel) (sel x y)))) ;Signature: car(pair) ;Type: [[ [T1*T2 -> T3] -> T3] -> T1] (define car (lambda (pair) (pair (lambda (x y) x)))) ;Signature: cdr(pair) ;Type: [[ [T1*T2 -> T3] ; -> T3] -> T2] (define cdr (lambda (pair) (pair (lambda (x y) y))))
30
applicative-eval[ (cons 1 2) ] ==> <closure (sel) (sel 1 2)> applicative-eval[ (car (cons 1 2 )) ] ==>* applicative-eval[ car ] ==> <closure (pair) (pair (lambda(x y) x))> applicative-eval[ (cons 1 2) ] ==>* <closure (sel) (sel 1 2) > sub, reduce: applicative-eval[ ( <closure (sel) (sel 1 2) > (lambda(x y) x) ) ] ==>* applicative-eval[ ( (lambda(x y) x) 1 2) ] ==> applicative-eval, sub, reduce: 1
31
Eager vs Lazy Eager Lazy
More work at constructions time. Immediate at selection time. Selectors that are not simple getters can have any arity. Immediate at construction time. More work at selection time. Selectors can be added freely, but must have the same arity.
32
Lazy Lists
33
Motivation: VERY Long (unlimited) Lists
(accumulate + 0 (enumerate-list )) We will need to create a (very) large list... If there was only a way not to...
34
Another Motivation Suppose we want the first prime number:
(car (filter prime? (enumerate_interval ))) We’ll have to calculate the whole list!
36
Lazy Lists (Streams) We need a new data type
Elements are not pre-computed Can be infinite! Implemented in a way that delays the computation We use lambdas! (what else…)
37
Lazy List In normal-order, all lists are lazy
In app-order, all lists are not lazy. All following are already evaluated: (cons head tail) (list e1 … en) (append l1 l2) (map p lst)
38
Lazy List: Constructor
Type language: LzL = ‘() | Scheme-type*[Empty -> LzL] empty – the empty lazy list cons (same as pair and list) [T * [Empty -> LzL] -> LzL] [T * [Empty -> LzL(T)] -> LzL(T)]
39
Simple Lazy List > (define l0 empty) > (define l1 (cons 1 (lambda () l0))) > (define l2 (cons 2 (lambda () l1))) > l0 ’() > l1 ’(1 . #<procedure>) > ((cdr l1)) > l2 ’(2 . #<procedure>) > ((cdr l2))
40
Real-World Example The recursion has no basis!
; [N -> ; N*[Empty -> LzL(N)]) (define integers-from (lambda (n) (cons n (lambda () (integers-from (add1 n)))))) > (define ints (integers-from 0)) > ints ’(0 . #<procedure>) > ((cdr ints)) ’(1 . #<procedure>) > ((cdr ((cdr ints)))) ’(2 . #<procedure>) The recursion has no basis!
41
Selectors ;Signature: head(lz-ist) ;Type:[T*[Empty -> LzL]) -> T] (define head car) ;Signature: tail(lz-ist) ;Type: [T*[Empty -> LzL]) -> LzL] (define tail (lambda (lz-lst) ((cdr lz-lst)))) > (head ints) 0 > (tail ints) (1. #<procedure>) > (head (tail ints)) 1 …
42
First n Elements ; Type: ; [LzL*N -> List] (define take (lambda (lz-lst n) (if (= n 0) empty (cons (head lz-lst) (take (tail lz-lst) (sub1 n)))))) > (take ints 3) ‘(0 1 2) > (take ints 0) ‘() > (take (integers-from 30) 7) ‘( )
43
The nth Element >(nth ints 44) 44
; Type: ; [LzL*N -> T] (define nth (lambda (lz-lst n) (if (= n 0) (head lz-lst) (nth (tail lz-lst) (sub1 n))))) >(nth ints 44) 44
45
Lazy Lists Lots of examples in following slides
My tip: always look for the cons
46
Integer Lazy List (define ones (cons 1 (lambda () ones))) >(take ones 7) ’( ) > (nth ones 10) 1 Now you see why we need a new type…
47
Factorial Lazy List (define facts-from (lambda (k) (letrec ((helper (lambda (n fact-n) (cons fact-n (lambda () (helper (add1 n) (* (add1 n) fact-n))))))) (helper k (fact k))))) (define facts-from-3 (facts-from 3)) > (take facts-from-3 6) ’( )
48
Fibonacci Lazy List (define fibs (letrec ((fibgen (lambda (a b) (cons a (lambda () (fibgen b (+ a b))))))) (fibgen 0 1))) > (take fibs 7) ’( )
49
Basic Lazy List Processing
If we want to manipulate a lazy-list, we need to construct another lazy-list Examples on next slides
50
Applying Square on Lazy List
; Type: [LzL(Num) -> LzL(Num)] (define squares (lambda (lz-lst) (if (empty? lz-lst) lz-lst (cons (sqr (head lz-lst)) (lambda () (squares (tail lz-lst))))))) > (take (squares ints) 7) ’( )
51
Lazy List Addition ; Type: [LzL(Num) * LzL(Num) -> LzL(Num)] (define lz-lst-add (lambda (lz1 lz2) (cond ((empty? lz1) lz2) ((empty? lz2) lz1) (else (cons (+ (head lz1) (head lz2)) (lambda () (lz-lst-add (tail lz1) (tail lz2))))))))
52
Defining Integers using Lazy List Addition
Reminder: (define ones (cons 1 (lambda () ones))) (define integers (cons 0 (lambda () (lz-lst-add ones integers)))) > (take integers 7) ’( )
53
Fibonacci Using Lazy List Addition
(define fib-numbers (cons 0 (lambda () 1 (lz-lst-add (tail fib-numbers) fib-numbers)))))) > (take fib-numbers 7) ’( )
54
Lazy List Map (define lz-lst-map (λ (f lz) (if (empty? lz) lz (cons (f (head lz)) (λ () (lz-lst-map f (tail lz))))))) > (take (lz-lst-map (lambda (x) (* x x)) ints) 5) ’( )
55
Lazy List Filter (define lz-lst-filter (λ (p lz) (cond ((empty? lz) lz) ((p (head lz)) (cons (head lz) (λ () (lz-lst-filter p (tail lz))))) (else (lz-lst-filter p (tail lz)))))) (define (divisible? x y) (= (remainder x y) 0)) (define no-sevens (lz-lst-filter (lambda (x) (not (divisible? x 7))) ints)) > (nth no-sevens 100) ;The 100th integer not divisible by 7: 117
56
Lazy List of Primes (define primes (cons 2 (λ () (lz-lst-filter prime? (integers-from 3)))))
57
Continuation Passing Style
58
Continuation Passing Style
Main idea: instead of returning a value, you pass it as a parameter to another function More specific: every user defined procedure f$ gets another parameter called continuation. When f$ ends we apply the continuation Distinction between creating the continuation and applying it All user defined function are in tail-position
59
Simple Examples: Normal CPS
(define square (lambda (x) (* x x))) (define add1 (+ x 1))) (define square$ (lambda (x cont) (cont (* x x))) (define add1$ (cont (+ x 1))))
60
(define square$ (lambda (x cont) (cont (
(define square$ (lambda (x cont) (cont (* x x))) (define add1$ (lambda (x cont) (cont (+ x 1)))) > (add1$ 5 (λ(x) x)) ( (λ(x) x) (+ 5 1) ) 6 > (square$ 5 (λ(x) x)) ( (λ(x) x) (* 5 5) ) 25 > (add1$ 5 (λ(x) (square$ x (λ(x) x)))) ( (λ(x) (square$ x (λ(x) x)))) (+ 5 1) ) ( (λ (x) x) 36 ) 36
61
Evaluation Order Order unknown We set the order
(define square$ (lambda (x cont) (cont (* x x))) (define add1$ (lambda (x cont) (cont (+ x 1)))) Order unknown We set the order (define h2 (λ (x y) (mult (square x) (add1 y)))) (define mult (* x y))) (define h2$ (λ (x y cont) (square$ x (λ (square-res) (add1$ y (λ (add1-res) (mult$ square-res add1-res cont))))))) Using LET will not help us. Why?
62
Does h2 equal to h2$ ? Claim: for every numbers x, y and continuation c: (h2$ x y c) = (c (h2 x y))
63
Proof a-e[ (h2$ x y cont) ] ==>* a-e[ (square$ x (λ (square-res) (add1$ y (λ (add1-res) (mult$ square-res add1-res cont))))) ] ==>* a-e[ ((λ (square-res) (add1$ y (λ (add1-res) (mult$ square-res add1-res cont)))) (* x x)) ] ==>* a-e[ (add1$ y (λ (add1-res) (mult$ x*x add1-res cont))) ] ==>* a-e[ ((λ (add1-res) (mult$ x*x add1-res cont)) (+ y 1)) ] ==>* a-e[ (mult$ x*x y+1 cont) ] ==>* a-e[ (cont (* x*x y+1)) ] = since a-e[ (* x*x y+1) ] = a-e[ (h2 x y) ] a-e[ (cont (h2 x y)) ]
64
In General A procedure f$ is CPS equivalent to a procedure f, if for every input value x1, x2,…,xn, n≥0: (f$ x1 … xn c) = (c (f x1 … xn))
65
So What’s the Big Deal? So we pass in a continuation. Doesn’t seem like a big deal, right? Things get more interesting when we work with recursions…
66
CPS is Good For: Order of computation (just seen)
Turning recursion into iteration (seen in the past, see more now) Returning multiple values The true power of CPS: Controlling multiple future computations
67
Recursion Into Iteration
(define fact (λ (n) (if (= n 0) 1 (* n (fact (- n 1)))))) (fact 3)
68
(define fact$ (λ (n cont) (if (= n 0) (cont 1) (fact$ (- n 1) (λ (res) (cont (* n res)))))))
נדגיש את המקומות בהם מפעילים את ה-continuation.
69
( (λ (res3) ( (λ (res2) ( (λ (res1) ( (λ (x) x) (. 3 res1))) (
( (λ (res3) ( (λ (res2) ( (λ (res1) ( (λ (x) x) (* 3 res1))) (* 2 res2))) (* 1 res3))) 1) ; ==> 2) ( (λ (x) x) 6) 6 (fact$ 3 (λ (x) x)) ; ==> (fact$ 2 (λ (res1) ((λ (x) x) (* 3 res1)))) 1 (λ (res2) ((λ (res1) ((λ (x) x) (* 3 res1))) (* 2 res2)))) 0 (λ (res3) ((λ (res2) (* 2 res2))) (* 1 res3))))
70
Proof that (fact$ n c) = (c (fact n))
Since fact is a recursive function, proof will be inductive.
71
בסיס האינדוקציה: a-e[ (fact$ 0 c) ] ==>* a-e[ (c 1) ] = a-e[ (c (fact 0)) ] הנחת האינדוקציה: עבור הטענה n=k מתקיימת לכל k≥i צעד האינדוקציה: יהא n=k+1, אזי: a-e[ (fact$ n c) ] ==>* a-e[ (fact$ (- n 1) (λ (res) (c (* n res)))) ] ==>* מהנחת האינדוקציה, נקבל: a-e [ ((λ (res) (c (* n res))) (fact (- n 1))) ] ==>* a-e [ (c (* n (fact (- n 1)))) ] = a-e [ (c (fact n)) ]
72
CPS Map (define map (λ (f lst) (if (empty? lst) lst (cons (f (car lst)) (map f (cdr lst)))))) (define map$ (λ (f$ list c) (if (empty? list) (c list) (f$ (car list) (λ (f-res) (map$ f$ (cdr list) (λ (map-cdr) (c (cons f-res map-cdr)))))))))
73
> (map$ (λ (x c) (c (. x x))) ‘(1 3) (λ (x) x)) ((λ (x c) (c (
> (map$ (λ (x c) (c (* x x))) ‘(1 3) (λ (x) x)) ((λ (x c) (c (* x x))) 1 (λ (f-res) (map$ (λ (x c) (c (* x x)) ‘(3) (λ (map-res) ( (λ (x) x) (cons f-res map-res)) )))))) (define map$ (λ (f$ list c) (if (null? list) (c list) (f$ (car list) (λ (f-res) (map$ f$ (cdr list) (λ (map-res) (c (cons f-res map-res)))))))))
74
Map$ Another Version (define map$ (λ (f$ list cont) (if (null? list) (cont list) (map$ f$ (cdr list) (λ (map-res) (f$ (car list) (λ (f-res) (cont (cons f-res map-res)))))))))
75
Multiple Future Computation
The true power of CPS Most useful example: errors Errors are unplanned future The primitive error breaks the calculation and returns void We want more control, and we can do it with CPS
76
Sum List with Error (define sumlist (lambda (li) (cond [(null? li) 0] [(not (number? (car li))) (error "non numeric value!")] [else (+ (car li) (sumlist (cdr li)))]))) (sumlist '(1 2 a)) במידה ויש איבר שאינו מס' אנו רוצים לעצור ולהחזיר שגיאה.
77
Try 1 (define sumlist (lambda (li) (cond ((null? li) 0) ((not (number? (car li))) (error "non numeric value!") 0) (else (+ (car li) (sumlist (cdr li))))))) האם זה יעזור?
78
Try 2 (define sumlist (lambda (li) (cond ((null? li) 0) ((not (number? (car li))) #f) (else (let ((sum-cdr (sumlist (cdr li)))) (if sum-cdr (+ (car li) sum-cdr) #f)))))) זה יעבוד חלקית: יחזור ערך, אבל הריצה לא תעצור באמצע.
79
Why is it so Complicated
We are deep inside the recursion: the stack is full with frames and we need to “close” every one of them If only there was a way NOT to open frames on the stack…
80
Sum List with CPS (define sumlist$ (λ (l succ fail) (cond [(empty? l) (succ l)] [(number? (car l)) (sumlist$ (cdr l) (λ (sum-cdr-l) (succ (+ (car l) sum-cdr-l))) fail)] [else (fail l)])))
81
Run Example (sumlist$ '(1 2 3 a) (lambda (x) x) (lambda (x) (display x) (display " ") (display 'not-a-num)))
82
Another Example: Using fail continuation in search
We search an unlabeled tree (actually a heterogeneous list). Once we find what we want the search stops. Tree ADT: Constructors: make-tree, add-subtree, make-leaf Selectors: first-subtree, rest-subtrees Predicates: composite-tree?, leaf?, empty-tree?
83
Fail Continuation For Backtracking
;; Purpose: Find the left most even leaf of a binary ;; tree whose leaves are labeled by numbers. ;; Type: [List -> Number union Boolean] ;; Examples: (leftmost-even ’((1 2) (3 4))) ==> 2 ;; (leftmost-even ’((1 1) (3 3))) ==> #f (define leftmost-even (λ (tree) (letrec ((iter (cond [(empty-tree? tree) #f] [(leaf? tree) (if (even? tree) tree #f)] [else (let ((res-first (iter (first-subtree tree)))) (if res-first res-first (iter (rest-subtrees tree))))])))) (iter tree)))) No CPS
84
Fail Continuation For Backtracking
(define leftmost-even$ (λ (tree succ-cont fail-cont) (cond [(empty-tree? tree) (fail-cont)] [(leaf? tree) (if (even? tree) (succ-cont tree) (fail-cont))] (else ; Composite tree (leftmost-even$ (first-subtree tree) succ-cont (λ () (rest-subtrees tree) fail-cont)))))))
85
(leftmost-even$ ((1 2) (3 4)) (λ (x) x) (λ () #f)) ==> (1 2) (λ () ((3 4)) (λ () #f)))) ;==>
(leftmost-even$ 1 (λ (x) x) (λ () (2) ((3 4)) (λ () #f)))))) ;==>* (λ () #f)))) ;==>* ( (λ (x) x) 2) ;==> 2
86
Moed A 2007
87
Solution (define scale-tree (λ (tree factor) (map (λ (sub-tree) (if (list? sub-tree) (scale-tree sub-tree factor) (* sub-tree factor))) tree))) (scale-tree '(((1 4) 2)) 5) (scale-tree '( ) 2)
89
Solution (define scale-tree$ (λ (tree factor c) (map$ (λ (sub-tree c) (if (list? sub-tree) (scale-tree$ sub-tree factor (λ (scale-sub-tree) (c scale-sub-tree))) (c (* sub-tree factor)))) tree c)))
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.