Practice session 6 Sequence Operations Partial Evaluation Lazy Lists The Sequence Interface רוצים לבצע פעולה כלשהי על מערך למשל לכתוב את הסימן ID: 254083
Download Presentation The PPT/PDF document "Principles of Programming Languages" is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.
Slide1
Principles of Programming Languages
Practice session 6
Sequence Operations
Partial Evaluation
Lazy ListsSlide2
The Sequence Interface
רוצים לבצע פעולה כלשהי על מערך
,
למשל
לכתוב את הסימן (
0,1,-1
) של כל אחד מהערכים.
ב-
Java
:
for(int i=0 ; i < arrayLength ; i
++){
if
( a[i] == 0 )
b[i
] = 0 ;
else
b[i
] = a[i]/abs(a[i]) ;
}
ב-
Scheme
:
(define
signs
(lambda (ls)
(
if (null? ls)
ls
(
if (= 0 (car ls))
(
cons 0 (signs (
cdr
ls
)))
(
cons (/ (car ls) (abs (car ls)))
(
signs (
cdr
ls)))))))Slide3
The Sequence Interface
רוצים לבצע פעולה כלשהי על אוסף, למשל לכתוב את הסימן (
0,1,-1
) של כל אחד מהערכים.
ב-
Scheme
:
(define
signs
(lambda (ls)
(
if (null? ls)
ls
(
if (= 0 (car ls))
(
cons 0 (signs (
cdr
ls
)))
(
cons (/ (car ls) (abs (car ls)))
(
signs (
cdr
ls
)))))))
באמצעות
map
:
(define
signs-map
(
lambda
(ls)
(
map
(lambda (x)
(
if (= x 0)
0
(/
x (abs x))))
ls
)))Slide4
The Sequence Interface
filter
: מסננת איברים מתוך רשימה. הסינון נעשה ע"י פונקציה המחזירה ערך בוליאני.
>(
filter
(lambda(x)(even? x))
(list 1 2 3 4 5 6))
'(2 4 6
)
שאלת חימום:
הפונקציה
partition
מקבלת
פונקציה בוליאנית
ורשימה,
ומחלקת את איברי הרשימה לאלו
שעומדים בתנאי
של הפונקציה ואלו שלא עומדים בתנאי. כיצד נממש
את
partition
באמצעות
map
ו-
filter
?
דוגמת הרצה:
>
(partition number? (list 1 2 3 'a 'b 'c 1 2 3 4 'd 'e 'f))
'((1 2 3 1 2 3 4) a b c d e f
)Slide5
The Sequence Interface
שאלת חימום:
הפונקציה
partition
מקבלת
פונקציה בוליאנית ורשימה ומחלקת את איברי הרשימה לאלו
שעומדים בתנאי
של הפונקציה ואלו שלא עומדים בתנאי. כיצד נממש
את
partition
?
דוגמת ריצה:
>
(partition number? (list 1 2 3 'a 'b 'c 1 2 3 4 'd 'e 'f))
'((1 2 3 1 2 3 4) a b c d e f
)
(
define partition
(
lambda (
pred
seq
)
(
cons (filter
pred
seq
)
(
filter (lambda (x)
(
not (
pred
x)))
seq
))))Slide6
The Sequence Interface
accumulate
:
הפעלת פעולה בינארית על איברי רש
ימה.
סדר הפעולות: פונקציית הפעולה הבינארית תופעל על האיבר האחרון ברשימה
ועל האיבר הניטרלי,
ולאחר מכן על
שאר האיברים,
מן הסוף
להתחלה,
כל פעם עם תוצאת ההפעלה הקודמת.
> (accumulate + 0 (list 1 2 3 4 5))15(+ 5 0) => 5(+ 4 5) => 9(+ 3 9) => 12…> (accumulate expt 1 (list 4 3 2))2621444^(3^(2^1 )) = 262144Slide7
The Sequence Interface
שאלה 2: אנו מעוניינים לממש את
הפרוצדורה
flat-sum
המקבלת רשימה מקוננת של רשימות
(עם
עומק קינון לא
ידוע)
ומחזירה
את סכום
כל האיברים בה
.
Signature: flat-sum(ls)Type: [List -> Number]Precondition: ls is recursively made of lists and numbers only.Examples: (flat-sum '(1 2 3 (1 2 (1 (1 2 3 4) 2 3 (1 2 3 4) 4) 3 4) 4)) => 50Slide8
The Sequence Interface
שאלה 2: אנו מעוניינים לממש את
הפרוצדורה
flat-sum
המקבלת רשימה מקוננת של רשימות
(עם
עומק קינון לא
ידוע)
ומחזירה
את סכום
כל האיברים בה
.
מימוש ללא ממשק sequence:(define flat-sum (lambda (ls) (cond ((null? ls) 0) ((number? ls) ls) ((let ((car-sum (flat-sum (car ls))) (cdr-sum (flat-sum (cdr ls)))) (+ car-sum cdr-sum))))))Slide9
The Sequence Interface
שאלה 2: אנו מעוניינים לממש את
הפרוצדורה
flat-sum
המקבלת רשימה מקוננת של רשימות
(עם
עומק קינון לא
ידוע)
ומחזירה
את סכום
כל האיברים בה
.
מימוש באמצעות sequence operations:(define flat-sum (lambda (lst) (acc + 0 (map (lambda (x) (if (number? x) x (flat-sum x))) lst))))
איך אפשר לייעל?Slide10
The Sequence Interface
(
define flat-sum
(
lambda (
lst
)
(
acc
+ 0
(
map
(lambda (x) (if (number? x) x (flat-sum x))) lst))))
(define flat-sum
(
let ((node->number
(
lambda (x)
(
if (number? x)
x
(
flat-sum x
))))) (lambda (ls) (accumulate + 0 (map node->number ls)))))
גרסה חדשה:Slide11
The Sequence Interface
שאלה 3:
בהינתן
רשימת
מספרים
אנו מעוניינים
לבטל כפילויות
ברשימה
ולמיינה
בסדר יורד ממש.
לשם פשטות, המיון יהיה מבוסס
insertion
sort . כיצד נממש?שלב I: מציאת איבר מקסימלי ברשימה:Signature: maximum(lst)Type: [List(Number) -> Number]Pre-Condition: lst contains only natural numbers (define maximum (lambda (lst) (acc (lambda (a b) (
if (> a b)
a
b
))
0
lst
)))Slide12
The Sequence Interface
שאלה 3:
בהינתן
רשימת
מספרים
אנו מעוניינים
לבטל כפילויות
ברשימה
ולמיינה
בסדר יורד ממש.
לשם פשטות, המיון יהיה מבוסס
insertion
sort . כיצד נממש?שלב II: מיון הרשימה:Signature: insertion-sort(lst)Type: [List(Number) -> List(Number)](define insertion-sort (lambda (lst) (if (null? lst) lst (let* ((max (maximum lst
)) (rest (filter (lambda (x)
(not (=
max x)))
lst
)))
(
cons max (insertion-sort rest))))))Slide13
Principles of Programming Languages
Practice session 6
Sequence Operations
Partial Evaluation
Lazy ListsSlide14
Partial Evaluation with Currying
שאלה 4: מימוש
accumulate
כפי שראיתם בהרצאה:
(define accumulate
(
lambda (op initial sequence)
(
if (null? sequence)
initial
(
op (car sequence)
(accumulate op initial (cdr sequence))))))Currying נאיבי:(define c-accumulate-naive (lambda (op initial) (lambda (sequence) (if (null? sequence) initial (op (car sequence) ((c-accumulate-naive op initial) (
cdr sequence)))))))Slide15
Partial Evaluation with Currying
Currying נאיבי
:
(define c-accumulate-naive
(
lambda (op initial)
(
lambda (sequence)
(
if (null?
sequence)
initial (op (car sequence) ((c-accumulate-naive op initial) (cdr sequence)))))))> (define add-accum (c-accumulate-naive + 0))> (add-accum '(1 2 3))6> (add-accum
'(4 5 6))15
נוצרים "הרבה"
Closure
-ים
Slide16
Partial Evaluation with Currying
Currying נאיבי
:
(define c-accumulate-naive
(
lambda (op initial)
(
lambda (sequence)
(
if (null?
sequence)
initial (op (car sequence) ((c-accumulate-naive op initial) (cdr sequence)))))))מימוש חכם יותר:(define c-accumulate-op-initial
(lambda (op initial) (
letrec
((
iter
(lambda (sequence)
(
if (null? sequence)
initial
(
op (car sequence) (
iter
(cdr sequence))))))) iter)))Slide17
Partial Evaluation with Currying
מימוש חכם יותר:
(define c-accumulate-op-initial
(lambda (op initial)
(
letrec
((
iter
(lambda (sequence)
(if (null? sequence)
initial
(op (car sequence) (
iter (cdr sequence))))))) iter)))> (define add-accum (c-accumulate-naive + 0))> (add-accum
'(1 2 3))6> (add-accum
'(4 5 6))
15
לא נוצרים
Closure
-ים
Slide18
Partial Evaluation with Currying
שאלה 4: שיערוך חלקי של
accumulate
–
נקודת מבט נוספת
:
Currying
נאיבי:
(define c-accumulate-naive
(lambda
(sequence)
(lambda
(op initial) (if (null? sequence) initial (op (car sequence) ((c-accumulate-naive (cdr sequence)) op initial))))))לא נאיבי:(define c-accumulate-sequence (lambda (sequence) (if (null? sequence) (lambda (op initial) initial) (let ((rest (c-accumulate-sequence (cdr sequence)))) (lambda (op initial)
(op (car sequence) (rest op initial)))))))Slide19
The Sequence Interface
שאלה 1: רוצים לממש את הפרוצדורה
dists_k
שמקבלת רשימה של זוגות מספרים המייצגים
קואורדינטות
(
x,y
)
, ומחזירה את המרחק מהראשית של כל הנקודות המקיימות
x=k
.Signature: dists_k (ls k)Type: [LIST(Number*Number) ->LIST(Number)]Examples: (dists_k (list (cons 3 4) (cons 3 7) (cons 15 12) (cons 3 12)) 3) => '(5 7.615773105863909 12.36931687685298)פונקציית העזר הנ"ל נתונה לנו:> (define dist (lambda (x y) (sqrt (+ (sqr x) (sqr y)))))Slide20
The Sequence Interface
שאלה 1: רוצים לממש את הפרוצדורה
dists_k
שמקבלת רשימה של זוגות מספרים המייצגים
קואורדינטות
(
x,y
)
, ומחזירה את המרחק מהראשית של כל הנקודות המקיימות
x=k
.> (define dist (lambda (x y) (sqrt (+ (sqr x) (sqr y)))))מימוש רקורסיבי, ללא ממשק Sequence:> (define dists_k (lambda (ls k) (if (null? ls) ls (let ((xcord (caar
ls)) (ycord
(
cdar
ls
))
(rest (
dists_k
(
cdr
ls) k))) (if (= xcord k) (cons (dist xcord ycord) rest) rest)))))Slide21
The Sequence Interface
שאלה 1: רוצים לממש את הפרוצדורה
dists_k
שמקבלת רשימה של זוגות מספרים המייצגים
קואורדינטות
(
x,y
)
, ומחזירה את המרחק מהראשית של כל הנקודות המקיימות
x=k
.> (define dist (lambda (x y) (sqrt (+ (sqr x) (sqr y)))))מימוש בעזרת ממשק Sequence:> (define dists_k (lambda (ls k) (map (lambda (x) (dist (car x) (cdr x))) (filter (lambda (x) (= (car x) k)) ls))))Slide22
Currying
שאלה 1:
רוצים לממש את הפרוצדורה
dists_k
שמקבלת רשימה של זוגות מספרים המייצגים
קואורדינטות
(
x,y
)
, ומחזירה את המרחק מהראשית של כל הנקודות המקיימות
x=k .>(define dist (lambda (x y) (sqrt (+ (sqr x) (sqr y)))))מימוש בעזרת ממשק Sequence:> (define dists_k (lambda (ls k) (map (lambda (x) (dist (car x) (cdr x))) (filter (lambda (x) (= (car x) k))
ls))))
שאלה 2:
מה אפשר לשפר במימוש הנ"ל?Slide23
Currying
שאלה 2:
>(define dist (lambda (x y) (
sqrt
(+ (
sqr
x) (
sqr
y)))))
> (define
c_dist
(lambda (x)
(let ((xx (sqr x))) (lambda(y) (sqrt (+ (sqr y) xx))))))מימוש dists_k החדש:> (define dists_k (lambda(ls k) (let ((dist_k
(c_dist k)))
(map (lambda (x)
(
dist_k
(
cdr
x)))
(filter (lambda (x)
(= (car x) k))
ls
)))))Slide24
Principles of Programming Languages
Practice session 6
Sequence Operations
Partial Evaluation
Lazy ListsSlide25
Lazy Lists
תזכורת: רשימות עצלות הן מבני נתונים סדרתיים המאפשרים דחייה של חישוב ושמירה של איברים מתוכם.
יתרונות
:
אין צורך לאחסן בזיכרון את כל איברי הרשימה.
ניתן אף לייצג
סדרות אין-סופיות.
דחיית חישוב איברים ברשימה לזמן בו נזדקק להם – ייתכן שלא נזדקק לכל איברי הרשימה.
הטיפוס של
LazyList
: LazyList = ‘() U T*[Empty->LazyList]Slide26
Lazy Lists
ממשק:Signature
: cons(head, tail)
Type:
[T * [Empty->
LazyList
] ->
LazyList
]
Purpose
: Value constructor for lazy lists
Signature: head(lzl)Type: [LazyList -> T]Purpose: Selector for the first item of lzl (a lazy list)Pre-condition: lzl is not empty Signature: tail(lzl)Type: [LazyList -> LazyList]Purpose: Selector for the tail (all but the first item) of lzl (a lazy list)Pre-condition: lzl is not empty Signature: nth(lzl, n)Type: [LazyList * Number -> T]Purpose: Gets the n-th item of lzl (a lazy list)Pre-condition: lzl length is at least n, n is a natural numberPost-condition: result=lzl[n-1] Signature: take(lzl, n) Type: [
LazyList * Number -> List] Purpose: Creates a List out of the first n items of lzl (a lazy list) Pre-condition:
lzl
length is at least n, n is a natural number
Post
-condition:
result[i]=
lzl
[i] for any i in range 0::n-1 Slide27
Lazy Lists
שאלה 5: רוצים לממש פונקציה שתיצור
lazy list
כנ"ל:
Signature
: integers-from (low)
Purpose
: Creates a lazy list containing all integers bigger than n-1 by their order
Pre-condition
: n is an integer
> (define integers-from
(lambda(n) (cons n (lambda () (integers-from (+ 1 n)))))) > (head (integers-from 5))5> (head (tail (integers-from 5))))6Slide28
Lazy Lists
שאלה 6: רוצים לממש רשימה שתספור לפי חוקי
7BOOM
.
(define seven-boom!
(
lambda (n)
(
cons
(
cond
((= (modulo n 7) 0) 'boom)
((has-digit? n 7) 'boom) (else n)) (lambda () (seven-boom! (+ n 1))))))> (seven-boom! 1)'(1 . #<procedure>) > (take (seven-boom! 1) 7)'(1 2 3 4 5 6 boom)Slide29
Lazy Lists
שאלה 7:
השערת
קולאץ
':
לכל מספר טבעי הרכבת הפונקציה על עצמה מגיעה ל-1.
רוצים להגדיר רשימה עצלה המכילה את סדרת
קולאץ
' עבור
n
כלשהו.
(define lzl-collatz (lambda (n) (if (< n 2) (cons n (lambda () (list))) (cons n (lambda () (if (= (modulo n 2) 0) (lzl-collatz (/ n 2)) (lzl-collatz (+ (* 3 n) 1 ))))))))Slide30
Lazy Lists
שאלה 8:
נרצה לממש את
filter
עבור רשימות עצלות
Signature
:
lzl
-filter(
pred
lzl
)Type: [[T -> Bool] * LazyList-> LazyList]Purpose: Creates a lazy list containing all members of lzl that fit criteria pred(define lzl-filter (lambda (pred lzl) (cond
((null? lzl) lzl
)
((
pred
(head
lzl
)) (
cons (head
lzl
)
(
lambda () (lzl-filter pred (tail lzl))))) (else (lzl-filter pred (tail lzl))))))רשימה עצלה של כל המספרים המתחלקים ב-k נתון כלשהו:> (lzl-filter (lambda (n) (= (modulo n k) 0)) (integers-from 0)Slide31
Lazy Lists
שאלה 7: רוצים לממש רשימה עצלה של המספרים הראשוניים ע"י שימוש בממשק
Sequence
.
>(define primes
(cons 2 (lambda()(
lz
-
lst
-filter prime? (integers-from 3)))))
>(define prime?
(lambda (n) (letrec ((iter (lambda (lz) (cond ((> (sqr (head lz)) n) #t) ((divisible? n (head lz)) #f) (else (iter (tail lz))))) )) (
iter (integers-from 2))) ))
> (take primes 6)
’(2 3 5 7 11 13)Slide32
Lazy Lists
שאלה 7: רוצים לממש רשימה עצלה של המספרים הראשוניים ע"י שימוש בממשק
Sequence
– אלגוריתם הנפה.
> (define sieve
(lambda (
lz
)
(cons (head
lz
)
(lambda ()
(sieve (lz-lst-filter (lambda(x) (not (divisible? x (head lz)))) (tail lz))))) )) > (define primes1 (sieve (integers-from 2)))