תוכן עניינים הקדמה
הכרות עם schemes
תבניות נתונים
תבניות
משפטי בקרה
משתנים לקסיקלים
רקורסיה
קלט/פלט
macros
מבנים
alises and tables ממשק המערכת
מחלקות ואובייקטים
jumps
אי-דטרמיניסטיות
מנועים
shell scripts
אתר ללימוד מקיף> פרק 3 - תבניות

פרק 3 - תבניות


הנושאים בפרק זה:
3.1.     פרוצדורות
          3.1.1. הפרמטרים של פרוצדורות
          3.1.2. מספר משתנה של ארגומנטים
3.2.     הפרוצדורה apply
3.3.     עריכה ברצף התוכניות שראינו עד כה גם הן s-expression. עובדה זו נכונה עבור כל תכנית בשפה Scheme. תוכניות הן נתונים.

לכן התו c#\ הוא תוכנית או תבנית. אנו נשתמש במושג תבנית ולא תוכנית, כדי שנוכל להבדיל גם בין קטעי תוכניות.
Scheme מעריכה את התו c#\ לערך c#\, מכיוון שהוא, מוערך עצמית.

לא כל ה-s-expression הם מוערכים עצמית. לדוגמא הסמל xyz s-expression מוערך לערך המוכל במשתנה xyz וכן הרשימה s-expression

(string -> number  "16")  

מוערכת למספר 16.
לא כל ה-s-expression הם תוכניות הגיוניות. אם נקליד ל-listener את הביטוי (1.2) ה-listener של Scheme יחשוב שזו טעות.
Scheme מעריכה תבנית של רשימה ע"י כך שהיא בוחנת את האיבר הראשון של התבנית. אם הוא מוערך לפרוצדורה אזי שאר האברים מוערכים לארגומנטים של הפרוצדורה והיא מופעלת עליהם.

אם ראש התבנית הוא תבנית מיוחדת הערכה מתקדמת באופן ייחודי על התבנית.
חלק מהתבניות המיוחדות כבר ראינו לדוגמא :begin , define ו-!set.
begin גורמת לשאר התת תבניות להיות מוערכות לפי הסדר והתוצאה של כל התבנית היא
התוצאה של התת תבנית האחרונה. define מאתחלת לראשונה את המשתנה ו-!set משנה את הקישורים של המשתנה.



לתחילת העמוד

3.1 פרוצדורות

הכרנו לא מעט פרוצדורות פרימיטיביות לדוגמא, string->list, cons ודומיהן.
משתמשים יכולים ליצור פרוצדורות משלהם ע"י שימוש בפרוצדורה מיוחדת lambda.
הדוגמא הבאה מגדירה פרוצדורה המוסיפה 2 לארגומנטים שלה:

(lambda (x) (+ x 2))

התת תבנית, (x), היא רשימה של פרמטרים. יתר תתי התבניות מהווים את גוף הפרוצדורה. ניתן לקרוא לפרוצדורה הנ"ל ע"י ארגומנט כפי שקוראים לפרוצדורות פרימיטיביות אחרות.

((lambda (x) (+ x 2)) 5)
=>  7

אם אנו רוצים לקרוא לאותה פרוצדורה כמה פעמים אנו יכולים ליצור העתק מדויק ע"י שימוש ב-lambda בכל פעם. אך ניתן לעשות זאת בדרך יעילה יותר, להשתמש במשתנה שיחזיק את ערך הפרוצדורה לדוגמא:

(define add2
  (lambda (x) (+ x 2)))

כעת אפשר להשתמש בפרוצדורה add2 בכל פעם שנרצה להוסיף 2 לארגומנטים.

(add2 4) =>  6
  (add2 9) =>  11



לתחילת העמוד

3.1.1 הפרמטרים של הפרוצדורות

הפרמטרים של הפרוצדורה lambda נמצאים בתת התבנית הראשונה (התבנית שבאה מיד לאחר המילה lambda) .
הפרוצדורה add2 היא פרוצדורה בעלת ארגומנט יחיד וכמוכן רשימת הארגומנטים (x) היא יחידה. הסמל x מתנהג כמשתנה המחזיק את ערך הפרוצדורה. כל הופעה של x בגוף הפרוצדורה, מתייחסת לארגומנט הפרוצדורה. x הוא משתנה מקומי בפרוצדורה.
אנו יכולים להשתמש ברשימות בעלות שני אלמנטים לפרוצדורות בעלות שני ארגומנטים ובאופן כללי n רשימות בעלות n אלמנטים לפרוצדורות בעלות n ארגומנטים.
הדוגמא הבאה היא פרוצדורה בעלת 2 ארגומנטים המחשבת שטח של מלבן. שני הארגומנטים הם האורך והרוחב של המלבן.

(define area 
           (lambda (length breadth) 
                  (* length breadth)))

יש לשים לב כי הפרוצדורה area מכפילה את הארגומנטים שלה כפי שעושה הפונקציה *.
יכולנו לכתוב בפשטות:

(define area *)



לתחילת העמוד

3.1.2 מספר משתנה של ארגומנטים

ישנם פרוצדורות אשר ניתן לקרוא להן מספר פעמים ובכל קריאה עם מספר שונה של ארגומנטים. כדי לבצע זאת רשימת הפרמטרים מוחלפת ע"י סמל יחיד .סמל זה מתנהג כמשתנה הקשור לרשימת ארגומנטים שהפרוצדורה קוראת להם.
באופן כללי רשימת הפרמטרים של lambda הם מהצורה: (x...), סמל או dotted-pair מהצורה של (x....z). במקרה של ה-dotted-pair כל המשתנים לפני הנקודה קשורים לארגומנטים המתאימים בקריאה לפרוצדורה, וארגומנט יחיד לאחר הנקודה שקולט את שאר הארגומנטים כרשימה אחת.



לתחילת העמוד

3.2 הפרוצדורה apply

פרוצדורה זו מאפשרת לנו לקרוא לפרוצדורה על רשימת הארגומנטים שלה.

(define x '(1 2 3))

(apply + x)
=>  6

באופן כללי, apply לוקחת פרוצדורה המלווה במספר ארגומנטים, שהאחרון חייב להיות רשימה. היא מרכיבה את רשימת הארגומנטים לרשימה ומחזירה את תוצאת הקריאה של הפרוצדורה על רשימת הארגומנטים.

לדוגמא

(apply + 1 2 3 x)
=>  12



לתחילת העמוד

3.3 עריכה ברצף

השתמשנו בתבנית המיוחדת של begin כדי לקבץ יחדיו קבוצה של תת תבניות שצריכות להיות מוערכות ברצף. begin מופיע בסוגים שונים של תבניות. לדוגמא נגדיר פרוצדורה בעלת שלושה ארגומנטים המציגה אותם עם רווחים ביניהם :

(define display3
  (lambda (arg1 arg2 arg3)
    (begin
      (display arg1)
      (display " ")
      (display arg2)
      (display " ")
      (display arg3)
      (newline))))

בשפה Scheme ,בגוף ה-lambda מופיע begin במרומז לכן ה-begin בפרוצדורה display3 לא נחוץ, אך הוא לא מזיק.
נכתוב את הפרוצדורה בצורה פשוטה יותר:

(define display3
  (lambda (arg1 arg2 arg3)
    (display arg1)
    (display " ")
    (display arg2)
    (display " ")
    (display arg3)
    (newline)))