חוקי דה־מורגן#
שתי זהויות, מאת אוגוסטוס דה־מורגן, כתובות מזה למעלה ממאה שנה בכל ספר לימוד של לוגיקה פורמלית, וצמד המשוואות השימושי ביותר שמתכנת עובד יכול להכיר.
¬(a ∧ b) ≡ ¬a ∨ ¬b
¬(a ∨ b) ≡ ¬a ∧ ¬b
במילים: דחיפת not דרך ביטוי בסוגריים הופכת כל אופרטור בפנים (∧ הופך ל־∨, ∨ הופך ל־∧) ושוללת כל אופרנד. באופן שקול: משיכת not החוצה הופכת כל אופרטור ומסירה את השלילות על האופרנדים.
מדוע זה חשוב ב־Perl#
unless הוא המקרה הקנוני. unless (X) הוא if (!X) — וברגע ש־X הוא בעצמו מורכב, יש לכם not מקדים מעל ביטוי בסוגריים: בדיוק המערך של דה־מורגן.
unless ($a == $x && $b == $y) { ... }
התנאי תחת ה־unless הוא !($a == $x && $b == $y). החילו את דה־מורגן: זהו !($a == $x) || !($b == $y). כל != הוא השלילה של ה־== המתאים, כך שהצורה הנקייה היא:
if ($a != $x || $b != $y) { ... }
שלוש טרנספורמציות התרחשו, כל אחת מכנית:
unlessהפך ל־if(ה־notהחיצוני).&&הפך ל־||(דה־מורגן, בפנים).==הפך ל־!=על כל אופרנד (השלילות שדה־מורגן הניח על האופרנדים מתבטלות לכדי ההשוואה ההפוכה).
זוהי לא העדפה סגנונית. כל מתכנת שאי־פעם איתר באג בתנאי שגוי בהה ב־unless (! ... && ...) דקה אחת יותר מדי; ה־if השטוח נקרא במעבר אחד.
דוגמה מפותחת#
צורה אמיתית, מסובכת מעט:
unless ($x !~ /^\d+$/ && $y !~ /^[a-z]+$/) {
print "at least one of \$x and \$y looks valid\n";
}
זה אומר: אלא אם $x לא־מספרי ו־$y לא־אלפביתי, הדפס. חמש שלילות ערוכות על פני שתי שורות. עברו על זה:
התנאי תחת ה־unless הוא
!( $x !~ /^\d+$/ && $y !~ /^[a-z]+$/ )
דה־מורגן הופך את ה־&& ל־|| ושולל כל צד:
!($x !~ /^\d+$/) || !($y !~ /^[a-z]+$/)
!($x !~ ...) הוא פשוט $x =~ ... (שלילה כפולה של התאמת regex). אותו דבר עבור הצד הימני:
$x =~ /^\d+$/ || $y =~ /^[a-z]+$/
אז הגרסה המנוקה היא:
if ($x =~ /^\d+$/ || $y =~ /^[a-z]+$/) {
print "at least one of \$x and \$y looks valid\n";
}
חמש שלילות הצטמצמו לאפס. התנאי כעת נקרא בדיוק כפי שההערה אמרה: אם $x הוא מספרי או $y הוא אלפביתי.
אותו טריק עבור OR#
הצורה השנייה של החוק היא המקרה הסימטרי:
unless ($a == 0 || $b == 0) { divide($a, $b) }
הופך ל
if ($a != 0 && $b != 0) { divide($a, $b) }
— אותם צעדים מכניים, רק שהפעם האופרטור הפנימי הוא || המתהפך ל־&&.
NAND, NOR — אותה זהות, נקראת בכיוון השני#
שורת ה־NAND בטבלת האמת מהפרק הקודם מכילה שני ערכים בעמודה ״Perl ניבי״:
14 NAND !($a && $b) / !$a || !$b
אלה שווים בגלל החוק הראשון של דה־מורגן. NAND הוא בדיוק השלילה של AND, ודחיפת השלילה פנימה הופכת את האופרטור ושוללת את האופרנדים. שורת ה־NOR פועלת באותה דרך עבור החוק השני:
8 NOR !($a || $b) / !$a && !$b
אז דה־מורגן אינו עובדה נפרדת שצריך לזכור לצד NAND ו־NOR — הוא הוא הזהות ההופכת איות אחד לאחר.
המכניקה, בפסקה אחת#
שלילה מתחלקת על פני ∧ ו־∨ על ידי היפוך הקשר ושלילת כל אופרנד. שלילה גם מבטלת את עצמה: ¬¬x ≡ x. שני הכללים יחד מאפשרים לכם לדחוף not עמוק כרצונכם, או למשוך אותו החוצה כרצונכם, מכל ביטוי הבנוי מ־∧, ∨, ו־¬. זהו כל התוכן של חוקי דה־מורגן — כל ״unless מסובך״ שאי־פעם שכתבתם הוא יישום אחד של שני כללים אלה בתוספת ביטול שלילה כפולה.
פרוצדורה מעשית#
כשאתם בוהים בתנאי שאינכם אוהבים:
אם מילת המפתח החיצונית היא
unless, הוסיפוnotמנטלית והפכו אותה ל־if.אם ה־
notהמקדים נמצא מעל&&או||בסוגריים, חלקו אותו: הפכו את הקשר, שללו כל אופרנד.אם תת־ביטוי הוא
!(x == y), החליפו ב־x != y. אותו דבר עבור!~↔=~,!defined↔defined, וכו«.עצרו כשאין יותר שלילות מקדימות לדחוף או יותר שלילות כפולות לבטל.
בפועל תבצעו את כל ארבעת השלבים בראשכם במעבר יחיד. הנקודה של הפרוצדורה היא שיש אחת — אינכם מחפשים את הצורה הנכונה, אתם נגזרים אליה.
מה כדאי לזכור מהפרק הזה#
שתי זהויות: דחיפת
¬דרך∧הופכת אותו ל־∨(ולהפך) ושוללת כל אופרנד.רוב ״ה־
unlessהמכוערים״ נמצאים היפוך דה־מורגן מכני אחד מ־ifנקי.NAND ו־NOR אינם עובדות נוספות; הם חוקי דה־מורגן הנקראים כצמד איותים שקולים.
ראו גם#
perlop — לוגי — מלווה מדריך העיון של האופרטורים. הטרנספורמציות של דה־מורגן כאן חלות על כל ביטוי Perl המשתמש ב־
&&,||,!, ובמילת המפתחunless.