Practice session 6 Sequence Operations Partial Evaluation Lazy Lists
רוצים לבצע פעולה כלשהי על מערך, למשל לכתוב את הסימן (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)))))))
רוצים לבצע פעולה כלשהי על אוסף, למשל לכתוב את הסימן (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)))
filter : מסננת איברים מתוך רשימה. הסינון נעשה ע " י פונקציה המחזירה ערך בוליאני. >(filter (lambda(x)(even? x)) (list )) '(2 4 6) שאלת חימום : הפונקציה partition מקבלת פונקציה בוליאנית ורשימה, ומחלקת את איברי הרשימה לאלו שעומדים בתנאי של הפונקציה ואלו שלא עומדים בתנאי. כיצד נממש את partition באמצעות map ו -filter? דוגמת הרצה : > (partition number? (list 'a 'b 'c 'd 'e 'f)) '(( ) a b c d e f)
שאלת חימום : הפונקציה partition מקבלת פונקציה בוליאנית ורשימה ומחלקת את איברי הרשימה לאלו שעומדים בתנאי של הפונקציה ואלו שלא עומדים בתנאי. כיצד נממש את partition ? דוגמת ריצה : > (partition number? (list 'a 'b 'c 'd 'e 'f)) '(( ) a b c d e f) (define partition (lambda (pred seq) (cons (filter pred seq) (filter (lambda (x) (not (pred x))) seq))))
accumulate : הפעלת פעולה בינארית על איברי רשימה. סדר הפעולות : פונקציית הפעולה הבינארית תופעל על האיבר האחרון ברשימה ועל האיבר הניטרלי, ולאחר מכן על שאר האיברים, מן הסוף להתחלה, כל פעם עם תוצאת ההפעלה הקודמת. > (accumulate + 0 (list )) 15 (+ 5 0) => 5 (+ 4 5) => 9 (+ 3 9) => 12 … > (accumulate expt 1 (list 4 3 2)) ^(3^(2^1 )) =
שאלה 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 ( ) 2 3 ( ) 4) 3 4) 4)) => 50
שאלה 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))))))
שאלה 2: אנו מעוניינים לממש את הפרוצדורה flat-sum המקבלת רשימה מקוננת של רשימות ( עם עומק קינון לא ידוע ) ומחזירה את סכום כל האיברים בה. מימוש באמצעות sequence operations: (define flat-sum (lambda (lst) (acc + 0 (map (lambda (x) (if (number? x) x (flat-sum x))) lst))))
(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)))))
שאלה 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)))
שאלה 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))))))
Practice session 6 Sequence Operations Partial Evaluation Lazy Lists
שאלה 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)))))))
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
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)))
מימוש חכם יותר : (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
שאלה 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)))))))
שאלה 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) => '( ) פונקציית העזר הנ " ל נתונה לנו : > (define dist (lambda (x y) (sqrt (+ (sqr x) (sqr y)))))
שאלה 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)))))
שאלה 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))))
שאלה 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: מה אפשר לשפר במימוש הנ " ל ?
שאלה 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)))))
Practice session 6 Sequence Operations Partial Evaluation Lazy Lists
תזכורת : רשימות עצלות הן מבני נתונים סדרתיים המאפשרים דחייה של חישוב ושמירה של איברים מתוכם. יתרונות : ◦ אין צורך לאחסן בזיכרון את כל איברי הרשימה. ניתן אף לייצג סדרות אין - סופיות. ◦ דחיית חישוב איברים ברשימה לזמן בו נזדקק להם – ייתכן שלא נזדקק לכל איברי הרשימה. הטיפוס של LazyList: LazyList = ‘() U T*[Empty->LazyList]
ממשק : 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 number Post-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
שאלה 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)))) 6
שאלה 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. # ) > (take (seven-boom! 1) 7) '( boom)
שאלה 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 ))))))))
שאלה 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)
שאלה 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) ’( )
שאלה 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)))