פרק 8: cut ושלילה

8.2 שלילה

נראה כעת שימוש נוסף חשוב של cut: היכולת להביע שלילה.

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

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

fail/0 הוא מתאר מיוחד בפרולוג, אשר תמיד נכשל. בפרולוג כשלון גם מכריח נסיגה וחיפוש פתרונות חלופיים (backtracking), דבר שבמקרה שלנו איננו רצוי: אנו רוצים שכאשר פרולוג ייתקל בספר של ג'יי קיי רולינג פרולוג ייכשל ולא יחפש פתרונות חלופיים. לשם כך נשתמש ב-cut, שכזכור כובלת אותנו לבחירות שעשינו וחוסמת אפשרויות נסיגה. הצירוף של cut ו-fail יחד יתן לנו את התוצאה המבוקשת.

אם כך, כאשר ניתקל בספר של ג'יי קיי רולינג נכריח את פרולוג להיכשל:

reads1(yossi, X) :-
author(X, j_k_rowling),!,fail.

אבל באופן כללי:

reads1(yossi, X) :-
fantasy(X).

שימו לב שיש חשיבות לסדר בין שני החוקים.

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

התכנית להורדה.

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

?- reads1(yossi, harry_potter).
No
?- reads1(yossi, the_hobbit).
Yes
?- reads1(yossi, the_lord_of_the_rings).
Yes
?- reads1(yossi, alice_in_wonderland).
Yes

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

עלינו למצוא דרך טובה יותר להביע את העובדה שיוסי לא קורא ספרים מאת ג'יי קיי רולינג. כלומר, עלינו למצוא דרך טובה יותר להביע שלילה. נשתמש בצירוף cut-fail, אבל נעטוף אותו במתאר מיוחד שיביע שלילה: lo (מלשון לא). שימוש בצירוף תכונות זה על מנת להביע שלילה נקרא שלילה על ידי כשלון (negation as failure).

lo(X) :- X, !, fail.
lo(X).

אם X מתקיים, אז נכשלים, ו-lo(X) נכשל. אם X לא מתקיים, החוק השני מצליח ומתקיים lo(X).

גרסא משופרת של הרגלי הקריאה של יוסי עושה שימוש במתאר lo:

reads2(yossi, X) :-
fantasy(X),
lo(author(X, j_k_rowling)).

למעשה פרולוג מכיל מתאר מערכת שמשמעותו בדיוק כמו זו של lo: +\. זהו אופרטור prefix שמשמעותו שלילה על ידי כשלון:

?- \+ reads2(yossi,harry_potter).
Yes

מילה של אזהרה:
למרות שהאופרטור +\ משמש אותנו להביע שלילה, הוא איננו שקול לאופרטור השלילה בלוגיקה. בלוגיקה הטענות "p וגם לא-q" ו- "לא-q וגם p" שקולות. לעומת זאת, בפרולוג יש חשיבות למיקום השלילה בתוך הגימום. בהגדרת reads2 הקפדנו לרשום את טענת השלילה בסוף הגימום. נגדיר reads3 שבו השלילה בהתחלה:

reads3(yossi, X) :-
\+ author(X, j_k_rowling),
fantasy(X).

כאשר אנו מנסים לקבל את רשימת הספרים שיוסי קורא, פרולוג עונה לנו תשובה תמוהה:

?- reads3(yossi,Book).
No

זו גם תשובתו בגרסא הראשונה, reads1. מה קורה כאן? פרולוג מצליח להוכיח את המטרה author(X, j_k_rowling) (על ידי האחדה בין X לבין harry_potter) ולכן נכשל בהוכחת שלילת הטענה. מכיוון שנכשל בהוכחת החלק הראשון של הגימום, הוא נכשל בהוכחת הגימום כולו, ועונה No. בגרסא השנייה, reads2, אנחנו קודם מציבים ערך ב-X ורק אז בודקים אותו. זו הדרך בה צריך לכתוב בפרולוג על מנת לקבל את ההתנהגות הנכונה:

?- reads2(yossi,Book).
Book = the_hobbit ;
Book = the_lord_of_the_rings ;
Book = alice_in_wonderland ;
No

מבוא

נושאים בסיסיים

נושאים מתקדמים

סיכום

© כל הזכויות שמורות למערכת המידע איתן