Recitation 11

advertisement
‫מבוא מורחב למדעי המחשב בשפת‬
‫‪Scheme‬‬
‫תרגול ‪11‬‬
‫‪1‬‬
Outline
• Mutable list structure
• RPN calculator
• Vectors and sorting
2
(define (set-to-wow! x)
(set-car! (car x) 'wow)
x)
(define x (list 'a 'b))
(define z1 (cons x x))
(define z2
(cons (list 'a 'b)
(list 'a 'b)))
(set-to-wow! z1)
((wow b) wow b)
(set-to-wow! z2)
((wow b) a b)
eq? point to the same object, equal? same content
(eq? (car z1) (cdr z1)) is true
(eq? (car z2) (cdr z2)) is false
3
Map without list copying
(define (map! f s)
(if (null? s) 'done
(begin
(set-car! s (f (car s)))
(map! f (cdr s)))))
(define s '(1 2 3 4))
(map! square s) => done
s => (1 4 9 16)
4
append!
(define (append! x y)
(set-cdr! (last-pair x) y)
x)
where:
(define (last-pair x)
(if (null? (cdr x))
x
(last-pair (cdr x))))
5
append vs. append!
(define x ‘(a b))
(define y ‘(c d))
(define z (append x y))
z ==> (a b c d)
(cdr x) ==> ?
(define w (append! x y))
w ==> (a b c d)
(cdr x) ==> ?
6
Cycle
(define (last-pair x)
(if (null? (cdr x))
x
(last-pair (cdr x))))
(define (make-cycle x)
(set-cdr! (last-pair x) x)
x)
(define z (make-cycle (list 'a 'b 'c)))
7
What happens?
z
a
b
c
(last-pair z) =>
8
is-cycle?
Examine the list and determine whether it contains a cycle, whether a
program that tried to find the end of the list by taking successive
cdrs would go into an infinite loop
(define (is-cycle? c)
(define (loop fast slow)
(cond ((null? fast) #f)
((null? (cdr fast)) #f)
((eq? (cdr fast) slow) #t)
(else (loop (cddr fast)
(cdr slow)))))
(loop c c))
9
Bounded Counter
A bounded counter can be incremented or decremented in
steps of 1, until upper and lower bounds are reached.
syntax:
(make-bounded-counter init bottom top)
example:
(define c (make-bounded-counter 3 1 5))
(counter-inc! c)  4
(counter-inc! c)  5
(counter-inc! c)  5
(counter-dec! c)  4
10
List Implementation
Constructor:
(define (make-bounded-counter init bottom top)
(list init bottom top))
Selectors:
(define (counter-value c) (car c))
(define (counter-bottom c) (cadr c))
(define (counter-top c) (caddr c))
11
List Implementation – cont.
Mutators:
(define (counter-inc! c)
(if (< (counter-value c) (counter-top c))
(set-car! c (+ 1 (counter-value c))))
(counter-value c))
(define (counter-dec! c)
(if (> (counter-value c) (counter-bottom c))
(set-car! c (- (counter-value c) 1)))
(counter-value c))
12
Polish Notation
• PostFix Notation: operands before operators
• Expressions with binary operators can be written without
Parentheses
• Apply operators, from left to right, on the last two numbers
– 5 7 4 - 2 * +
– 5
3 2 * +
– 5
6 +
–
11
• Stack implementation:
– Init: Empty stack
– Number: insert! Into stack
– Operator: apply on 2 top stack elements and
insert! result into stack
13
Simulation
(calc)
5
7
4
TOP= 3
2
*
TOP= 6
+
TOP= 11
exit
ok
14
Read & Eval
• (read) - returns an expression from the user
• (eval exp) - evaluates an expression
• We will use these functions in:
– (perform m) - receives a symbol of an operation,
applies it on the two top numbers in the stack, and
returns the result to the stack
– (iter) - reads an input from the user. If it is a
number it is pushed to the stack, if it is an operator we
call perform
15
perform
(define (perform m)
(let ((arg2 ((stk 'top))))
((stk 'delete!))
(let ((arg1 ((stk 'top))))
((stk 'delete!))
((stk 'insert!)
((eval m) arg1 arg2)))))
16
iter
(define (iter)
(let ((in (read)))
(if (eq? in 'exit)
'ok
(begin
(cond ((number? in)
((stk 'insert!) in))
(else
(perform in)
(display "TOP= ")
(display ((stk 'top)))
(newline)))
17
(iter)))))
Calc
(define (calc)
(let ((stk (make-stack)))
(define (perform m) ...)
(define (iter) ... )
(iter)))
18
Vectors
Constructors:
(vector v1 v2 v3 . . .)
(make-vector size init)
Selector:
(vector-ref vec place)
Mutator:
(vector-set! vec place value)
Other functions:
(vector-length vec)
19
Example - accumulating
(define (accumulate-vec op base vec)
(define (helper from to)
(if (> from to) base
(op (vector-ref vec from)
(helper (+ from 1) to))))
(helper 0 (- (vector-length vec) 1)))
20
Bucket Sort
• Problem: Sorting numbers that distribute “uniformly”
across a given interval (for example, [0,1) ).
• Observation: The number of elements that fall within
a sub-interval is proportional to the sub-interval’s size
• Idea:
–
–
–
–
Divide into sub-intervals (buckets)
Throw each number into appropriate bucket
Sort within each bucket (any sorting method)
Adjoin all sorted buckets
21
Example
Sorting:
0.31 0.44 0.72 0.89 0.10
0.05 0.97 0.23 0.56 0.68
If we want ~3 numbers in each bucket, we need 3-4
buckets. Using 3 buckets we have:
Bucket 0.000 - 0.333: 0.31 0.10 0.05 0.23
Bucket 0.333 – 0.667: 0.44 0.56
Bucket 0.667 – 1
: 0.72 0.89 0.97 0.68
Now sort!
Bucket 0.000 - 0.333: 0.05 0.10 0.23 0.31
Bucket 0.333 – 0.667: 0.44 0.56
Bucket 0.667 – 1
: 0.68 0.72 0.89 0.97
22
Analysis
• Observation: If number of buckets is proportional
to the number of elements, then the number of
elements in each bucket is more or less the same,
and bounded by a constant.
•
•
•
•
Dividing into buckets: O(n)
Sorting one bucket: O(1)
Sorting all buckets: O(n)
Adjoining sorted sequences: O(n)
23
Implementation
• A bucket is a list
• The set of buckets is a vector
• The elements are sorted while inserted into the buckets
(very similar so insertion sort):
(define (insert x s)
(cond ((null? s) (list x))
((< x (car s)) (cons x s))
(else (cons (car s)
(insert x (cdr s))))))
24
Implementation – for-each
• Scheme primitive
• Similar to map, without returning a value
• Useful for side-effects
(define (for-each proc lst)
(if (null? lst) ‘done
(begin (proc (car lst))
(for-each proc
(cdr lst)))))
25
Implementation – cont.
(define (bucket-sort s)
(let* ((size 5)
(n (ceiling (/ (length s) size)))
(buckets (make-vector n null)))
(define (insert! x)
(let ((bucket (inexact->exact (floor (* n x)))))
(vector-set! buckets bucket
(insert x (vector-ref buckets bucket)))))
(for-each insert! s)
(accumulate-vec append null buckets)))
26
Streams
3.5, pages 316-352
definitions file on web
27
cons, car, cdr
(define s
(cons 9 (begin (display 7) 5)))
-> prints 7
The display command is evaluated while
evaluating the cons.
(car s)
-> 9
(cdr s)
-> 5
28
cons-stream, stream-car,
stream-cdr
(define s
(cons-stream 9 (begin (display 7) 5)))
Due to the delay of the second argument,
cons-stream does not activate the display command
(stream-car s)
-> 9
(stream-cdr s)
-> prints 7 and returns 5
stream-cdr activates the display which
prints 7, and then returns 5.
29
List enumerate
(define (enumerate-interval low high)
(if (> low high) nil
(cons low
(enumerate-interval
(+ low 1) high))))
(enumerate-interval 2 8)
-> (2 3 4 5 6 7 8)
(car (enumerate-interval 2 8))
-> 2
(cdr (enumerate-interval 2 8))
-> (3 4 5 6 7 8)
30
Stream enumerate
(define (stream-enumerate-interval low high)
(if (> low high) the-empty-stream
(cons-stream low
(stream-enumerate-interval
(+ low 1) high))))
(stream-enumerate-interval 2 8)
-> (2 . #<promise>)
(stream-car (stream-enumerate-interval 2 8))
-> 2
(stream-cdr (stream-enumerate-interval 2 8))
-> (3 . #<promise>)
31
List map
(map <proc> <list>)
(define (map proc s)
(if (null? s) nil
(cons
(proc (car s))
(map proc (cdr s)))))
(map square (enumerate-interval 2 8))
-> (4 9 16 25 36 49 64)
32
Stream map
(map <proc> <stream>)
(define (stream-map proc s)
(if (stream-null? s) the-empty-stream
(cons-stream
(proc (stream-car s))
(stream-map proc (stream-cdr s))
)))
(stream-map square
(stream-enumerate-interval 2 8))
-> (4 . #<promise>)
33
List of squares
(define squares
(map square
(enumerate-interval 2 8)))
squares
-> (4 9 16 25 36 49 64)
(car squares)
-> 4
(cdr squares)
-> (9 16 25 36 49 64)
34
Stream of squares
(define stream-squares
(stream-map square
(stream-enumerate-interval 2 8)))
stream-squares
-> (4 . #<promise>)
(stream-car stream-squares)
-> 4
(stream-cdr stream-squares)
-> (9 . #<promise>)
35
List reference
(define (list-ref s n)
(if (= n 0) (car s)
(list-ref (cdr s) (- n 1))))
(define squares
(map square
(enumerate-interval 2 8)))
(list-ref squares 3)
-> 25
36
Stream reference
(define (stream-ref s n)
(if (= n 0) (stream-car s)
(stream-ref (stream-cdr s) (- n 1))))
(define stream-squares
(stream-map square
(stream-enumerate-interval 2 8)))
(stream-ref stream-squares 3)
-> 25
37
List filter
(filter <predicate> <list>)
(define (filter pred s)
(cond
((null? s) nil)
((pred (car s))
(cons (car s) (filter pred (cdr s))))
(else (filter pred (cdr s)))))
(filter even? (enumerate-interval 1 20))
-> (2 4 6 8 10 12 14 16 18 20)
38
Stream filter
(stream-filter <predicate> <stream>)
(define (stream-filter pred s)
(cond
((stream-null? s) the-empty-stream)
((pred (stream-car s))
(cons-stream
(stream-car s)
(stream-filter pred (stream-cdr s))))
(else (stream-filter pred (stream-cdr s)))
)))
(stream-filter even?
(stream-enumerate-interval 1 20))
39
-> (2 . #<promise>)
Generalized list map
(generalized-map <proc> <list1> … <listn>)
(define (generalized-map proc . arglists)
(if (null? (car arglists)) nil
(cons
(apply proc (map car arglists))
(apply generalized-map
(cons proc (map cdr arglists))))))
(generalized-map + squares squares squares)
-> (12 27 48 75 108 147 192)
40
Generalized stream map
(generalized-stream-map <proc> <stream1> … <streamn>)
(define (generalized-stream-map proc . argstreams)
(if (stream-null? (car argstreams))
the-empty-stream
(cons-stream
(apply proc (map stream-car argstreams))
(apply generalized-stream-map
(cons proc (map stream-cdr argstreams))))))
(generalized-stream-map +
stream-squares stream-squares stream-squares)
-> (12 . #<promise>)
41
List for each
(define (for-each proc s)
(if (null? s) 'done
(begin
(proc (car s))
(for-each proc (cdr s)))))
42
Stream for each
(define (stream-for-each proc s)
(if (stream-null? s) 'done
(begin
(proc (stream-car s))
(stream-for-each proc (stream-cdr s)))))
useful for viewing (finite!) streams
(define (display-stream s)
(stream-for-each display s))
(display-stream (stream-enumerate-interval 1
43
20)) -> prints 1 … 20 done
Lists
(define sum 0)
(define (acc x) (set! sum (+ x sum)) sum)
(define s (map acc (enumerate-interval 1 20)))
s -> (1 3 6 10 15 21 28 36 45 55 66 78 91 105
120 136 153 171 190 210)
sum -> 210
(define y (filter even? s))
y -> (6 10 28 36 66 78 120 136 190 210)
sum -> 210
(define z (filter
(lambda (x) (= (remainder x 5) 0)) s))
z -> (10 15 45 55 105 120 190 210) sum -> 210
44
(list-ref y 7)
-> 136
sum -> 210
(display z)
-> prints (10 15 45 55 105 120 190 210)
sum -> 210
45
Streams
(define sum 0)
(define (acc x) (set! sum (+ x sum)) sum)
(define s (stream-map
acc (stream-enumerate-interval 1 20)))
s -> (1 . #<promise>)
sum -> 1
(define y (stream-filter even? s))
y -> (6 . #<promise>)
sum -> 6
(define z (stream-filter
(lambda (x) (= (remainder x 5) 0)) s))
z -> (10 . #<promise>)
sum -> 10
46
(stream-ref y 7)
-> 136
sum -> 136
(display-stream z)
-> prints 10 15 45 55 105 120 190 210 done
sum -> 210
47
Defining streams implicitly
by delayed evaluation
Suppose we needed an infinite list of Dollars.
We can
(define bill-gates
(cons-stream ‘dollar bill-gates))
If we need a Dollar we can take the car
(stream-car bill-gates) -> dollar
The cdr would still be an infinite list of
Dollars.
(stream-cdr bill-gates)->(dollar . #<promise>)
48
Infinite Streams
Formulate rules defining
infinite series
wishful thinking is key
49
1,1,1,… = ones =
1,ones
(define ones
(cons-stream 1 ones))
50
2,2,2,… = twos =
2,twos
(define twos (cons-stream 2 twos))
ones + ones
adding two infinite series of ones
(define twos (stream-map + ones ones))
2 * ones
element-wise operations on an infinite series of ones
(define twos (stream-map
(lambda (x) (* 2 x)) ones))
or (+ x x)
51
1,2,3,… = integers =
1,ones + integers
1,1,1…
+
1,2,3,…
2,3,4,…
(define integers
(cons-stream 1
(stream-map + ones integers)))
52
0,1,1,2,3,… = fibs =
0,1,fibs + (fibs from 2nd position)
0,1,1,2,…
+
1,1,2,3,…
1,2,3,5,…
(define fibs
(cons-stream 0
(cons-stream 1
(stream-map +
fibs (stream-cdr fibs)))))
53
1,2,4,8,… = doubles =
1,doubles + doubles
1,2,4,8,…
+
1,2,4,8,…
2,4,8,16,…
(define doubles (cons-stream 1
(stream-map + doubles doubles)))
54
1,2,4,8,… = doubles =
1,2 * doubles
(define doubles (cons-stream 1
(stream-map
(lambda (x) (* 2 x)) doubles)))
or (+ x x)
55
1,1x2,1x2x3,... = factorials =
1,factorials * integers from 2nd
position
1, 1*2, 1*2*3,…
x
2, 3,
4,…
1*2,1*2*3,1*2*3*4,…
(define factorials (cons-stream 1
(stream-map * factorials
(stream-cdr integers))))
56
(1),(1 2),(1 2 3),… = runs =
(1), append runs with a list of
integers from 2nd position
(1), (1 2), (1 2 3),…
append
(2), (3),
(4),…
(1 2),(1 2 3),(1 2 3 4),…
(define runs (cons-stream (list 1)
(stream-map append runs
(stream-map list
(stream-cdr integers)))))
57
a0,a0+a1,a0+a1+a2,… =
partial sums =
a0,partial sums + (stream from 2nd pos)
a0,
a0+a1,
a0+a1+a2,…
+
a1,
a2,
a3,…
a0+a1,a0+a1+a2,a0+a1+a2+a3,…
(define (partial-sums a) (cons-stream
(stream-car a)
(stream-map +
(partial-sums a)
(stream-cdr a))))
58
Partial Sums (cont.)
(define (partial-sums a)
(define sums
(cons-stream (stream-car a)
(stream-map +
sums
(stream-cdr a))))
sums)
This implementation is more efficient since it uses the
stream itself rather than recreating it recursively
59
Repeat
Input: procedure f of one argument,
number of repetitions
Output: f*…*f, n times
(define (repeated f n)
(if (= n 1) f
(compose f (repeated f (- n 1)))))
(define (compose f g)
(lambda (x) (f (g x))))
60
Repeat stream
f,f*f,f*f*f,… = repeat =
f,compose f,f,f,… with repeat
(define f-series
(cons-stream f f-series))
(define stream-repeat
(cons-stream f
(stream-map compose
f-series stream-repeat)))
We would like f to be a parameter
61
Repeat stream
f,f*f,f*f*f,… = repeat =
f,compose f,f,f,… with repeat
(define (make-repeated f)
(define f-series
(cons-stream f f-series))
(define stream-repeat
(cons-stream f
(stream-map compose
f-series stream-repeat)))
stream-repeat)
62
Interleave
1,1,1,2,1,3,1,4,1,5,1,6,…
(interleave ones integers)
s0,t0,s1,t1,s2,t2,… interleave =
s0,interleave (t, s from 2nd position)
(define (interleave s t)
(if (stream-null? s) t
(cons-stream
(stream-car s)
(interleave t (stream-cdr s)))))
63
Download