De Morgan’s laws#
Two identities, due to Augustus De Morgan, written for over a century in every textbook of formal logic, and the single most useful pair of equations a working programmer can know.
¬(a ∧ b) ≡ ¬a ∨ ¬b
¬(a ∨ b) ≡ ¬a ∧ ¬b
In words: pushing a not through a parenthesised expression flips
every operator inside (∧ becomes ∨, ∨ becomes ∧) and
negates each operand. Equivalently: pulling a not out flips
every operator and removes the negations on the operands.
Why this matters in Perl#
unless is the canonical case. unless (X) is if (!X) — and the
moment X is itself a compound, you have a leading not over a
parenthesised expression: exactly the De Morgan setup.
unless ($a == $x && $b == $y) { ... }
The condition under the unless is !($a == $x && $b == $y).
Apply De Morgan: this is !($a == $x) || !($b == $y). Each !=
is the negation of the corresponding ==, so the clean form is:
if ($a != $x || $b != $y) { ... }
Three transformations happened, each mechanical:
unlessflipped toif(the outernot).&&flipped to||(De Morgan, inside).==flipped to!=on each operand (the negations De Morgan placed on the operands cancel into the opposite comparison).
This is not a stylistic preference. Every programmer who has
debugged a wrong condition has stared at unless (! ... && ...) for
a minute too long; the flat if reads in one pass.
A worked example#
A real shape, slightly tangled:
unless ($x !~ /^\d+$/ && $y !~ /^[a-z]+$/) {
print "at least one of \$x and \$y looks valid\n";
}
This says: unless $x is non-numeric and $y is non-alphabetic,
print. Five negations stacked across two lines. Walk through it:
The condition under the unless is
!( $x !~ /^\d+$/ && $y !~ /^[a-z]+$/ )
De Morgan flips the && to || and negates each side:
!($x !~ /^\d+$/) || !($y !~ /^[a-z]+$/)
!($x !~ ...) is just $x =~ ... (double negation of a regex
match). Same for the right side:
$x =~ /^\d+$/ || $y =~ /^[a-z]+$/
So the cleaned-up version is:
if ($x =~ /^\d+$/ || $y =~ /^[a-z]+$/) {
print "at least one of \$x and \$y looks valid\n";
}
Five negations down to zero. The condition now reads exactly the
way the comment said it: if $x is numeric or $y is alphabetic.
The same trick for OR#
The second form of the law is the symmetric case:
unless ($a == 0 || $b == 0) { divide($a, $b) }
becomes
if ($a != 0 && $b != 0) { divide($a, $b) }
— same mechanical steps, only this time the inner operator is ||
flipping to &&.
NAND, NOR — same identity, read the other way#
The NAND row in the truth table from the previous chapter has two entries in the “Perl idiomatic” column:
14 NAND !($a && $b) / !$a || !$b
These are equal because of De Morgan’s first law. NAND is exactly the negation of AND, and pushing the negation in flips the operator and negates the operands. The NOR row works the same way for the second law:
8 NOR !($a || $b) / !$a && !$b
So De Morgan is not a separate fact you have to remember alongside NAND and NOR — it is the identity that turns one spelling into the other.
Mechanics, in one paragraph#
Negation distributes over ∧ and ∨ by flipping the connective
and negating each operand. Negation also self-cancels: ¬¬x ≡ x.
The two rules together let you push a not arbitrarily deep, or
pull it arbitrarily out, of any expression built from ∧, ∨, and
¬. That is the whole content of De Morgan’s laws — every
“convoluted unless” you ever rewrite is one application of those
two rules plus double-negation cancellation.
Practical procedure#
When you stare at a condition you don’t like:
If the outer keyword is
unless, prepend anotmentally and make itif.If the leading
notis over a parenthesised&&or||, distribute it: flip the connective, negate each operand.If a subexpression is
!(x == y), replace withx != y. Same for!~↔=~,!defined↔defined, etc.Stop when there are no more leading negations to push or no more double-negations to cancel.
In practice you will do all four steps in your head in a single pass. The point of the procedure is that there is one — you are not searching for the right form, you are deriving it.
What you should remember from this chapter#
Two identities: pushing
¬through∧flips it to∨(and vice versa) and negates each operand.Most “ugly
unless” is one mechanical De Morgan flip away from a cleanif.NAND and NOR are not extra facts; they are De Morgan’s laws read as a pair of equivalent spellings.