1 / 37

Variations on scheme

Variations on scheme. Variable Declarations: lazy and lazy-memo. Handle lazy and lazy-memo extensions in an upward-compatible fashion.; (lambda (a (b lazy) c (d lazy-memo)) ...) "a", "c" are normal variables (evaluated before procedure application

julie-avery
Télécharger la présentation

Variations on scheme

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Variations on scheme

  2. Variable Declarations: lazy and lazy-memo • Handle lazy and lazy-memo extensions in an upward-compatible fashion.; (lambda (a (b lazy) c (d lazy-memo)) ...) • "a", "c" are normal variables (evaluated before procedure application • "b" is lazy; it gets (re)-evaluated each time its value is actually needed • "d" is lazy-memo; it gets evaluated the first time its value is needed, and then that value is returned again any other time it is needed again.

  3. Syntax Extensions – Parameter Declarations (define (first-variable var-decls) (car var-decls)) (define (rest-variables var-decls) (cdr var-decls)) (define declaration? pair?) (define (parameter-name var-decl) (if (pair? var-decl) (car var-decl) var-decl)) (define (lazy? var-decl) (and (pair? var-decl) (eq? 'lazy (cadr var-decl)))) (define (memo? var-decl) (and (pair? var-decl) (eq? 'lazy-memo (cadr var-decl))))

  4. thunk- memo exp env when forced evaluated-thunk result Controllably Memo-izing Thunks • thunk – never gets memoized • thunk-memo – first eval is remembered • evaluated-thunk – memoized-thunk that has already been evaluated

  5. A new version of delay-it • Look at the variable declaration to do the right thing... (define (delay-it decl exp env) (cond ((not (declaration? decl)) (l-eval exp env)) ((lazy? decl) (list 'thunk exp env)) ((memo? decl) (list 'thunk-memo exp env)) (else (error "unknown declaration:" decl))))

  6. Change to force-it (define (force-it obj) (cond ((thunk? obj) ;eval, but don't remember it (actual-value (thunk-exp obj) (thunk-env obj))) ((memoized-thunk? obj) ;eval and remember (let ((result (actual-value (thunk-exp obj) (thunk-env obj)))) (set-car! obj 'evaluated-thunk) (set-car! (cdr obj) result) (set-cdr! (cdr obj) '()) result)) ((evaluated-thunk? obj) (thunk-value obj)) (else obj)))

  7. Changes to l-apply • Key: in l-apply, only delay "lazy" or "lazy-memo" params • make thunks for "lazy" parameters • make memoized-thunks for "lazy-memo" parameters (define (l-apply procedure arguments env) (cond ((primitive-procedure? procedure) ...) ; as before; apply on list-of-arg-values ((compound-procedure? procedure) (l-eval-sequence (procedure-body procedure) (let ((params (procedure-parameters procedure))) (extend-environment (map parameter-name params) (list-of-delayed-args params arguments env) (procedure-environment procedure))))) (else (error "Unknown proc" procedure))))

  8. Deciding when to evaluate an argument... • Process each variable declaration together with application subexpressions – delay as necessary: (define (list-of-delayed-args var-decls exps env) (if (no-operands? exps) '() (cons (delay-it (first-variable var-decls) (first-operand exps) env) (list-of-delayed-args (rest-variables var-decls) (rest-operands exps) env))))

  9. Summary • Lazy evaluation – control over evaluation models • Convert entire language to normal order • Upward compatible extension • lazy & lazy-memo parameter declarations

  10. How do we use this new lazy evaluation? • Our users could implement a stream abstraction: (define (cons-stream x (y lazy-memo)) (lambda (msg) (cond ((eq? msg 'stream-car) x) ((eq? msg 'stream-cdr) y) (else (error "unknown stream msg" msg))))) (define (stream-car s) (s 'stream-car)) (define (stream-cdr s) (s 'stream-cdr)) OR (define (cons-stream x (y lazy-memo)) (cons x y)) (define stream-car car) (define stream-cdr cdr)

  11. Stream Object cons-stream stream-cdr stream-car a value a thunk-memo

  12. Review

  13. Review: Final last spring ברצוננו להוסיף למשעך המטה-מעגלי (meta-circular evaluator) אפשרות לטיפול בשגרות בעלות מספר ארגומנטים לא קבוע תוך שמוש ב- dotted-tail notation. אם ברשימת הפרמטרים של שגרה מופיעה נקודה לפני הפרמטר האחרון אז כאשר קוראים לשגרה זאת יקבלו הפרמטרים שמופיעים לפני הנקודה, אם יש כאלו, את ערכם בצורה הרגילה, והפרמטר האחרון יקבל רשימה שמורכבת מכל שאר הארגומנטים. למשל, אם נשערך (define (f x y . z) (cons (list x y) z) (f 1 2 3 4) אז בעת הפעלת הפונקציהf יקשרx ל- 1, y יקשר ל- 2 ו- z יקשר לרשימה (4 3). התוצאה שתוחזר תהיה על כן ( (1 2) 3 4) כמובן שניתן להשתמש ב- dotted-tail notation גם בביטוייlambda ולהגדיר את השגרהf באופן הבא (define f (lambda (x y . z) (cons (list x y) z)))

  14. כתוב/י שגרהremove-dot שמקבלת כקלט רשימת פרמטרים שכוללת אולי נקודה לפני הפרמטר האחרון. על השגרה להחזיר רשימה בת שני איברים. האיבר הראשון הוא מספר הפרמטרים שמופיעים לפני הנקודה, או המספר הכולל של הפרמטרים אם אין ברשימת הקלט נקודה. האיבר השני ברשימת הפלט הוא רשימת כל הפרמטרים ללא הנקודה. למשל: (remove-dot ‘(x y . z))  ( 2 (x y z)) (remove-dot ‘(x y z))  ( 3 (x y z) ) (remove-dot ‘(. x))  ( 0 (x) )

  15. (define (remove-dot lst) (cond ((null? lst) (list 0 lst)) ((eq? (car lst) ’.) (list 0 (cdr lst))) (else (let ((x (remove-dot (cdr lst)))) (list (+ 1 (car x)) (cons (car lst) (cadr x)))))))

  16. mc-eval משתמש בשגרהmake-procedure שמוגדרת באופן הבא: (define (make-procedure parameters body env) (list ‘procedure parameters body env)) שנה/י את הגדרתmake-procedure כך שתוכל לטפל גם במקרה ובוparameters הוא רשימת פרמטרים עם נקודה בתוכה. העצם הפרוצדורלי שייוצר ע"יmake-procedure צריך להיות רשימה באורך חמש, במקום באורך ארבע כמקודם. האיבר השני ברשימה זאת צריך להיות מספר הפרמטרים הכולל, במקרה ואין נקודה, או מספר הפרמטרים שהופיעו לפני הנקודה, אם יש נקודה. האיבר השלישי יהיה רשימת כל הפרמטרים (ללא הנקודה). האיבר הראשון ברשימה, ושני האיברים האחרונים בה יהיו כמקודם. (define (make-procedure parameters body env) (let ((x (remove-dot parameters))) (list 'procedure (car x) (cadr x) body env)))

  17. השלם/י את הגדרת השגרה (split-list lst n) שמקבלת רשימהlst ומספרn. ניתן להניח שהאורך שלlst הוא לפחותn. על השגרה להחזיר רשימה ש- n האיברים הראשונים בה הםn האיברים הראשונים שלlst. אם יש ב- lst עוד איברים, אז האיבר האחרון ברשימת הפלט יהיה רשימת האיברים שנותרו ב-lst. למשל: (split-list ‘(1 2 3 4) 4)  (1 2 3 4) (split-list ‘(1 2 3 4) 2)  (1 2 (3 4)) (split-list ‘(1 2 3 4) 0)  ((1 2 3 4)) (define (split-list lst n) (if (= n 0) (if (null? lst) '() (list lst)) (cons (car lst) (split-list (cdr lst) (- n 1)))))

  18. בסעיפים הנותרים של שאלה זאת את/ה מתבקש לתאר את השינויים שיש לבצע, אם בכלל, ב-eval ב-apply וכן אולי בשגרות אחרות, בכדי שהמשערך ידע לטפל בצורה נכונה בשגרות שהוגדרו תוך שמוש ב-dotted-tail notation. האם יש צורך לבצע שינויים בהגדרתeval ? אם כן, תאר את השינויים הדרושים. האם יש צורך לבצע שינויים בהגדרתapply ? אם כן, תאר את השינויים הדרושים.

  19. (define (mc-apply procedure arguments) (cond ((primitive-procedure? procedure) (apply-primitive-procedure procedure arguments)) ((compound-procedure? procedure) (eval-sequence (procedure-body procedure) (extend-environment (procedure-parameters procedure) (split-list arguments (procedure-before-dot procedure)) (procedure-environment procedure)))) (else (error "Unknown procedure type -- APPLY" procedure))))

  20. .האם יש צורך לבצע שינויים בשגרות אחרות ? אם כן, תאר את השינויים הדרושים. (define (procedure-before-dot p) (cadr p)) (define (procedure-parameters p) (caddr p)) (define (procedure-body p) (cadddr p)) (define (procedure-environment p) (cadddr (cdr p)))

  21. Final last spring f(k) אםf ו-g הן פונקציות, נסמן ב- את הפונקציה שמתקבלת ע"י הפעלתk f פעמים, וב-f*g את ההרכבה שלf ו-g. למשל, אםf(x)=x2אזf(3)(x)=f(f(f(x)))=x8. אם בנוסף לכךg(x)=x+1 אז 2(f*g)(x)=(x+1). השלם/י את מימוש השגרה (iterate f n) שמקבלת שגרהf ומספר טבעיn ומחזירה שגרה שמחשבת את. אםn=0, על השגרה להחזיר את העתקת הזהות. f(n) (define (iterate f n) (if (= n 0) _______________ ________________________________________)) (define (iterate f n) (if (= n 0) (lambda (x) x) (lambda (x) (f ((iterate f (- n 1)) x)))))

  22. Final last spring (Cont) השלם/י את הגדרת השגרה (duplicate x n) שמקבלת איברx ומחזירה רשימה באורךn שכל איבריה הםx. (lambda (y) (cons x y)) n) '() (define (duplicate x n) ((iterate __________________________) ___ ))

  23. Final last spring (Cont) השלם/י את הגדרת השגרה (int-lst n) שמקבלת מספרn ומחזירה את רשימת המספרים .(1 2 . . n) (lambda (x) (cons (- (car x) 1) x)) (- n 1)) (list n))) (define (int-lst n) ((iterate ______________________________________________) _________ ))

  24. Final last spring (Cont) .השלם את מימוש השגרה (compose fns) שמקבלת רשימת זוגותfns מהצורה( (f1 . n1) (f2 . n2) … (fk . nk) ) כאשרf1,f2,…,fkהן שגרות ו- n1,n2,…,nkהם מספרים טבעיים ומחזירה שגרה שמחשבת את f1(n1)*f2(n2)*…*fk(nk ) (lambda (x) x) (caar fns) (cdar fns) (cdr fns) (lambda (x) ((iterate f1 n1) ((compose rest) x))) (define (compose fns) (if (null? fns) ________________ (let ((f1 __________) (n1 __________) (rest __________)) _____________________________________________ )))

  25. בשאלה זאת נתאים לכל מספר טבעי רשימה שמורכבת מהספרות שלו (בייצוג העשרוני). למספר 0, תתאים הרשימה הריקה . למספר 1 תתאים הרשימה (1)’. למספר 4 תתאים הרשימה (4)’. למספר 13 תתאים הרשימה (3 1)’, וכך הלאה. (שימו לב שספרת האחדות היא הספרה הראשונה ברשימה). • ממש שגרה (increment dig-list) שמקבלת רשימה, dig-list, שמייצגת מספר מסויםn ומחזירה את הרשימה שמייצגת את המספרn+1.

  26. (define (increment n1) (if (null? n1) '(1) (let ((digit (car n1))) (if (= digit 9) (cons 0 (increment (cdr n1))) (cons (+ digit 1) (cdr n1)))))) • ממש שגרה (increment! dig-list) שמקבלת רשימה, dig-list, שמייצגת מספר מסויםn ומחזירה את הרשימה שמייצגת את המספרn+1. • לשגרה זו מותר להגדיר תאי-cons חדשים רק במידה ויש בכך צורך. לדוגמא:

  27. (define (add1! n1) (if (null? n1) '(1) (let ((digit (car n1))) (if (= digit 9) (begin (set-car! n1 0) (add1! (cdr n1))) (set-car! n1 (+ digit 1))))) n1) ממש פרוצדורהodd-1-digits, המחזירהstream המכיל את כל המספרים הטבעיים, שבייצוג העשרוני שלהם מופיעה הספרה 1 מספר אי-זוגי של פעמים . כל מספר בזרם מיוצג ע"י רשימת ספרותיו בייצוגו העשרוני כמו בסעיפים הקודמים (בסדר ספרות הפוך). (stream-car (odd-1-digits))  (1) (stream-car (stream-cdr (odd-1-digits)))  (0 1)

  28. (define (odd-1-digits) (define ints (cons-stream ____________ (stream-map _____________________ ))) (stream-filter ______________________________________________ ______________________________________________ ______________________________________________ ints)) ‘() add1 ints (lambda (y) (odd? (accumulate + 0 (filter (lambda (x) (= x 1)) y))))

  29. f g 9 5 4 3 בשאלה זאת נעסוק במבנה נתונים מופשט הקרוי עץ-חישוב. עץ-חישוב הוא עץ שבכל צומת פנימי שלו רשומה פונקציה, ושבכל עלה שלו רשום איבר. בציור מוצג כדוגמא עץ-חישוב שמורכב משני צמתים פנימיים שבהם רשומות הפונקציותf ו-g וארבעה עלים שמהם מופיעים המספרים 3, 4, 9 ו- 5. ערכו של עץ-חישוב נקבע ע"פ ההגדרה הרקורסיבית הבאה. אם עץ-החישוב מורכב מעלה בודד, אז ערכו מוגדר כערך שרשום בעלה זה. אחרת, מתקבל ערך עץ-החישוב ע"י הפעלת הפונקציה שרשומה בשורש עץ-החישוב על ערכי תתי-העצים של עץ-החישוב. ערכו של עץ-החישוב שמופיע בציור הוא, למשל, f(g(3,4),9,5)

  30. לצורך טיפול בעצי-חישוב, עומדות לרשותך השגרות הבאות: (leaf? tree) --- בודק האם העץtree מורכב מעלה בודד. (one-child? tree) --- בודק האם לשורש העץtree בן אחד בלבד. (content tree) --- מחזיר את תוכנו של שורש עץ-החישובtree. (children tree) --- מחזיר רשימה של תתי העצים של השורש שלtree. (left-child tree) --- מחזיר את תת העץ השמאלי ביותר שלtree. (rest tree) --- מחזיר את העץtree לאחר הורדת תת העץ השמאלי ביותר שלו.

  31. השלם את הגדרת השגרהeval-tree שמקבלת כארגומנט עץ-חישוב ומחזירה את ערכו (define (eval-tree tree) (if (leaf? tree) ____________________________________ _________________________________________________ __________________________________________________)) (content tree) (apply (content tree) (map eval-tree (children tree)))

  32. נתרכז עתה בעצי-חישוב בוליאניים. עץ-חישוב בוליאני הוא עץ-חישוב שבעליו מופיעים רק האיברים 0 ו- 1, ושבצמתיו הפנימיים מופיעות רק הפונקציותlor ו-land, כאשרlor מחזירה את הערך 1 אם ורק אם לפחות אחד מהארגומנטים שלה הוא 1, ו- 0 אחרת, בעוד ש-land מחזירה את הערך 1 אם ורק אם כל הארגומנטים שלה הם 1, ו- 0 אחרת. (גםlor וגםland מקבלות מספר כלשהו של ארגומנטים.) (אינכם נדרשים לממש אתlor ו-land.) ניתן כמובן להשתמש בשגרהeval-tree בכדי לשערך עצי-חישוב בוליאניים אך דבר זה הוא לפעמים מאוד בזבזני. אם נסתכל למשל על עץ-החישוב הבוליאני הבא, נשים לב שניתן לקבוע שערכו הוא 1 מבלי בכלל לבדוק את תוכן העלים שתוכנם מסומן בסימן שאלה.

  33. or ? 1 and ? 0

  34. באופן כללי ניתן לחשב את ערכו של עץ-חישוב בוליאני ע"י האלגוריתם הרקורסיבי הבא: אם העץ מורכב מעלה בודד, החזר את ערך העלה. אחרת, שערך בזה אחר זה, משמאל לימין, את תתי-העצים שמהם מורכב העץ עד שניתן לקבוע בצורה חד משמעית את ערך העץ. השלם את ההגדרה הבאה של השגרהeval-bool-tree שמממשת את האלגוריתם היעיל לשערוך עצי-חישוב בוליאניים. הנח שעומדת לרשותך השגרה (lor? tree) שבודקת אם הפונקציה שמופיעה בשורש העץtree היא הפונקציהlor.

  35. (define (eval-bool-tree tree) (if (leaf? tree) __________________ (let ((tmp (eval-bool-tree ______________ ) ) ) (if (or (one-child? ______________ ) (and (= tmp 1) (lor? _______) ) __________________________ __________________________ __________________________ )))) (content tree) (left-child tree) tree tree (and (= tmp 0) (not (lor? tree)))) tmp (eval-bool-tree (rest tree))

  36. בסעיפים הבאים ננסה לקבל מימוש חליפי של השגרהeval-bool-tree תוך שמוש בזרמים (streams). כתוב שגרה (lor-stream s) שמקבלת זרםs, סופי או אינסופי, שכל איבריו הם 0 או 1. על השגרה לעבור בזה אחר זה על איברי הזרםs עד שימצא איבר שערכו 1. אם נמצא איבר כזה, על השגרה להחזיר את הערך 1. אם הזרםs הוא סופי וכל איבריו הם אפסים, על השגרה להחזיר את הערך 0. (אםs הוא אינסופי וכל איבריו הם אפסים, חישוב (lor-stream s) לא יסתיים לעולם.) (define (lor-stream s) (let ((x (stream-filter (lambda (x) (= x 1)) s))) (if (stream-null? x) 0 1)))

  37. הנח עתה שבנוסף לשגרות לטיפול בעצי-ביטויים שהוזכרו קודם, עומדת לרשותך גם השגרה (children-stream tree) שמחזירה זרם שאיבריו הם תתי-העצים שלtree. הנח שעומדת לרשותך גם שגרה בשם (land-stream s) שפועלת בדומה לשגרהlor-stream אך מחשבת את ה-land אל איברי הזרםs. השלם את המימוש הבא שלeval-bool-tree : (define (eval-bool-tree tree) (if (leaf? tree) _________________ ( (if (lor? tree) ______________ _______________) (stream-map _____________ ____________________ ) ) ) ) (content tree) lor-stream land-stream eval-bool-tree (children-stream tree)

More Related