הפשטה כמושג מרכזי בהוראת מדעי המחשב: סקר ספרות

תכנות לוגי כשפה התומכת בהפשטה והוראתה

מ. גינדי

קטעים מתוך: גינדי, מ., תכנות לוגי כפרדיגמה תומכת הפשטה והוראתה, עבודה סמינריונית בקורס: ממדעי המחשב להוראתם- רקע, התפתחות וסוגיות נבחרות, האוניברסיטה הפתוחה, 2004, (בהנחיית ב., הברמן).   

 

כל החומרים עומדים לרשותכם וניתן להשתמש בהם להוראה ללא תשלום.

שימו לב: לא ניתן לעשות בחומר הזה כל שימוש מסחרי ללא רשות בכתב מראש מיוצרי החומרים.

 

תכנות לוגי ושפת פרולוג הנלמדות במסגרת תכנית הלימודים

בעשור האחרון החלו בלימוד פרדיגמת תכנות לוגי, כדוגמה לפרדיגמת תכנות דקלרטיבית, בבתי ספר תיכוניים כחלק מתכנית הלימודים במדעי המחשב, תוך שימוש בשפת פרולוג כשפה המייצגת פרדיגמה זו. שפת פרולוג מבוססת על תיאור וייצוג של הסקת מסקנות אנושית במונחים של לוגיקה פורמלית והיא שונה בתכלית מהשפות הפרוצדוראליות הרגילות. בשפות אלו, משתמשים בניסוח סידרת תהליכים המכתיבים למכונה איך לפתור בעיה מסוימת. פרולוג, לעומת זאת, משתמשת בהצהרות לוגיות במטרה לתאר מה הבעיה שיש לפתור (Scherz, Maler, Shapiro, 1986).

במאמרם, מציינים Scherz,  Goldbergו- Fund (1990) שלוש סיבות עיקריות ללימוד פרולוג ברמת בית ספר תיכון. ראשית, שפת פרולוג היא שפה אקסיומטית דקלרטיבית שניתן להשתמש בה כאמצעי להצגת תכנים לוגיים של תחומי עניין מגוונים כגון מדעי החיים, מדעים מדויקים ואף מדעי החברה ובלשנות. לדעת המחברים, תלמידים המתכנתים בפרולוג לומדים לבנות את הידע שלהם באמצעות הגדרת הקשרים בין המושגים הרלוונטיים, והדבר עוזר להם בהפנמת ידע זה. שנית, שפת פרולוג מעניקה הזדמנות ללמוד חלק מהמושגים והרעיונות של הלוגיקה הפורמלית בתוספת המוטיבציה והדרבון להיות מסוגלים להריץ אותם על המחשב וזאת ללא צורך בהבנה מעמיקה בפורמליות המסובכת של הלוגיקה המתמטית. הסיבה השלישית היא שפרולוג היא שפה עדכנית וחזקה המייצגת שפות תכנות שמדעני מחשב רבים מאמינים שתהפוכנה בולטות בעתיד. ועדין, זוהי שפה , ידידותית וקלה ללימוד, המזכירה שפה טבעית.

 

הפשטת פעולות בתכנות לוגי

בנוסף על האמור, שפת פרולוג נותנת ביטוי רב  לעקרון הפשטת פעולות בהקשר של ייצוג הבעיה באמצעות יחסי בסיס פשוטים (basic relationships). בשפה זו מוצג פתרון לבעיה באמצעות אוסף של טענות, טענות אלו ניתנות לכתיבה בצורה הדומה מאוד לשפת הדיבור הרגילה שלנו ולכן קלה יותר להבנה ולהפנמה, תכונה זו של שפת פרולוג תורמת רבות בהפנמה ובשימוש במושג ההפשטה. אסביר טענה זו באמצעות דוגמה פשוטה למימוש תכנית לייצוג משפחה בשפת פרולוג, נגדיר תחילה עובדות בסיסיות כגון:

% זכר( _אדם)

% נקבה(_אדם)   

% אב(_אב , _ילד )

% אם(_אם, _ילד)             

 

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

 

ראשית נגדיר:

% הורה(_הורה, _ילד):

הורה(X, Y):- אב(X, Y).

הורה(X, Y):- אם(X, Y).

 

וכעת נגדיר:

%אח(_אדם, _אחיו_של_אדם):

אח(X, Y):-

                הורה(Z, Y),

                הורה(Z, X),

                X \= Y,

                זכר(Y).

 

הגדרות אלו תואמות במידה רבה את שפת הדיבור ואת צורת המחשבה שלנו. כאן באה לידי ביטוי ההפשטה, כשם שבשפת הדיבור היומיומית שלנו יותר סביר שנאמר "דני אח של יוסי" ולא: "דני הוא זכר, דני הוא הבן של משה ויוסי הוא הבן של משה" (מה שאומר שהם אחים)  כך גם בשפת פרולוג, יהיה הגיוני ופשוט יותר למתכנת להשתמש במתאר הקיים: אח(_אדם, _אחיו_של_אדם)  מבלי לפרט שוב בכל פעם שיש צורך את העובדות המפורטות בתוך המתאר. ובאופן דומה, כאשר נרצה להגדיר את המתאר בן_דוד(_אדם, בן_דוד), נגדיר תחילה את המתאר דוד(_אדם, _ דוד):

 

% דוד(_אדם, _ דוד):

דוד ( X, Y):-

                אח( X, Z),

                הורה( Z, Y).

 

וכעת נשתמש במתאר זה לצורך הגדרת " בן_דוד(_אדם, בן_דוד)":

% בן_דוד(_אדם, בן_דוד):

בן_דוד(X, Y):-

                דוד(Z, X),

                הורה(Z, Y),

זכר(Y).

 

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

פיתוח מסוג זה הינו פיתוח תוך שימוש בהפשטת פעולות בגישת bottom-up "מלמטה למעלה" כלומר, מגדירים פעולה חדשה באמצעות פעולה שהוגדרה קודם לכן. יכולנו, באותה מידה, לבחור בגישת top-down "מלמעלה למטה", שיטה זו מדגישה אף יותר את מושג ההפשטה, ולמעשה עוזרת מן הסתם בהפנמת שימוש בעיקרון הסתרת מידע. כלומר, ניתן להצרין פעולה, קרי מתאר חדש, באמצעות משהו שטרם הוצרן, או משהו שאין הכרח לדעת את אופן הצרנתו. וכך, ניתן לראות כי בתכנות לוגי ניתנת בחירה בנוגע לסדר המימוש של המתארים והפעולות, ואין חובה לממש מתאר לפני השימוש בו, בניגוד לשפת פסקל, שבה חייב המתכנת לכתוב תחילה את כל הפעולות בהם הוא משתמש בתכניתו, ורק אחר כך להשתמש בהן. בצורה זו ניתן "לחנך" את התלמידים לעבוד בשני הכיוונים ולהעריך את החיוניות של כל אחד מהם.

 

הפשטת נתונים בתכנות לוגי

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

 

% פרטים_אישיים( שם( _שם_משפחה, _שם_פרטי), מספר_תז( _תז)).

? פרטים_אישיים( X, _)).

X= שם( כהן, רינה).

? פרטים_אישיים( שם(כהן, X ), _)).          % אופן זה מאפשר גישה לפרטי המארז.

X= רינה.

 

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

 

% צומח( רשימת_רשימות_צמחים).

צומח ( [ [ורד, נרקיס, רקפת], [ ברוש, אלון, צפצפה], [תפוז, זית, בננה]]).

? צומח( X ).

X=  [ [ורד, נרקיס, רקפת], [ ברוש, אלון, צפצפה], [תפוז, זית, בננה]]

? צומח( [X, [ ברוש, אלון, צפצפה], [תפוז, זית, בננה]]).

X=  [ורד, נרקיס, רקפת].

? צומח( [ [ורד, נרקיס, רקפת], [ X, אלון, צפצפה], [תפוז, זית, בננה]]).

X= ברוש.

 

לטיפוס הנתונים רשימה מלווה ממשק המספק יחסים ופעולות (כגון היחסים "קודם", "עוקב" , "חבר", "ראשון ברשימה" וכד') המתאימים לטיפוס זה והמבטאים הפשטת פעולות עליו. בהמשך נראה דוגמה של תכנית בפרולוג העושה שימוש ברשימה ופעולותיה.

 

הפשטה בתכנות לוגי באמצעות שימוש בטיפוסי נתונים מופשטים

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

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

לקופסאות השחורות של טיפוסי נתונים מופשטים ישנם שני מרכיבים: מרכיב המימוש ומרכיב הממשק. בפרולוג, מרכיב המימוש מכיל הגדרות של מתארים כללים המייצגים את הפעולות והקשרים המוגדרים במודל, אשר מוחבאים מהמשתמש לפי עקרון הסתרת המידע. ומנגד, מרכיב הממשק גלוי למשתמש ומתאר את המתארים הכלליים: כל מתאר מאופיין באמצעות שמו, רשימת הארגומנטים שלו ומשמעותם, היחסים המוגדרים באמצעותו, והנחות בסיסיות הנוגעות לדרך הפניה למתאר במהלך תהליך התכנות (Haberman, Shapiro, Scherz, 2002) . למעשה, פתרון בעיה באמצעות שימוש בטיפוסי נתונים מופשטים משקף עיקרון של הפשטת פעולות.

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

לדוגמה, נציג מימוש של מעין "מאגר מידע" של סוגי פרחים העושה שימוש בקופסה השחורה של טיפוס הנתונים רשימה ובפעולות המוגדרות עליה:

 

רמת שאילתות:

? סוג_פרח(_איזה).                                             ? מספר_סוגי_פרחים(_כמה).

_איזה = ורד                                                         _כמה = 3

 

רמת התכנית:

% מתארי בעיה קונקרטיים:

% סוגי_פרחים( רשימת פרחים מסויימת)

סוגי_פרחים([ורד, כלנית, נרקיס]).

 

% מתארי בעיה כלליים:

% סוג_פרח(_פרח)

סוג_פרח(_פרח):-

                סוגי_פרחים(_רשימה_נתונה),

                חבר(_פרח, _רשימה_נתונה).

 

% מספר_סוגי_פרחים(_מספר_פרחים):

מספר_סוגי_פרחים(_מספר):-

                                סוגי_פרחים(_רשימה_נתונה),

                                מספר_איברים(_מספר, _ רשימה_נתונה).

 

רמת הקופסה השחורה של טיפוס הנתונים המופשט רשימה:

% חבר(_איבר, _רשימה)

חבר(X, [_ | X] ).

חבר(X, [_ |Y ] ):-

                                חבר(X, Y).

%מספר_איברים(_מספר, _רשימה)

מספר_איברים( 0, [ ] ).

מספר_איברים(N, [ _ | Y] ):-

                                מספר_איברים( P, Y),

                                N הוא  P + 1.

 

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

 

מבנים בשפה התומכים בהפשטה- השוואה בין התכנות הלוגי והתכנות הפרוצדורלי.

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

 

חזרה לעמוד הראשי