On Clean Dishes, and Being Positive
About our new dishwasher…
A couple of years ago I taught a course called ‘Introduction to Artificial Intelligence Programming’ — largely because I was available when no-one else was. It turned out to be great fun, and not least because I’d been through the same course one year as a student, and another as a Teaching Assistant, and could finally teach it the way I wanted to.
The course had been moving towards trendy-but-hardly-AI stuff like Java, so I was happy to yank it back to the delights of Prolog, and basic AI techniques like state-space search.
Prolog is a fantastic way to approach programming, for various reasons. You can’t help but learn about logic too — you’re basically programming with a subset of first-order predicate logic. You absolutely can’t hack it, the way that you can with most procedural languages. If you’re not exactly sure what a piece of code you’ve written means, it’ll bite back, hard. It’s a perverse joy to see students go through the Three Stages of Prolog. The First Stage is: ‘Bah. This is just a toy. It couldn’t possibly be actually useful for anything.’ The Second Stage is: ‘SHIT. This suddenly got hard and I don’t understand it any more.’ (The Second Stage only really exists because of the First Stage, which gives them a lethally false sense of security.) The Third Stage, which most (but not all) reach, is: ‘Oh, I get it.’ That light-bulb moment is wonderful to see, when it happens. It’ll never be unclear to them again.
Prolog is to AI programming as Latin is to natural language. You don’t just learn the language — indeed, in some ways that’s the least thing that you learn. Latin teaches you about language itself. Prolog teaches you about AI: formal logics, knowledge representation and inference, search strategies.
Anyway, about our new dishwasher…
One of the small-but-important rules of thumb that I tried to teach the students on the course was not to define some predicate in terms of the conditions under which it isn’t true. A Prolog clause might look like this:
mortal(X) :- man(X).
— which says that some property, ‘mortal’, is true of some thing, ‘X’, if some other property, ‘man’, is also true of that thing. ‘Every man is mortal’, in other words. And that’s fine. On the other hand:
not_immortal(X) :- man(X).
Logically, this is completely equivalent, since (one assumes):
not_immortal(X) :- mortal(X).
But clarity, which is every bit as important as logical soundness, goes flying out of the window. Consider how we might define ‘immortal’ using our original definition of ‘mortal’:
immortal(X) :- \+ mortal(X).
The \+ symbol is the typical Prolog symbol to represent a logical ‘not’, so this reads: ‘Something is immortal if it isn’t mortal’ (assuming a closed world), and that’s clear enough. Consider now how we’d define ‘immortal’ using our second definition of mortality:
immortal(X) :- \+ not_immortal(X).
That’s: ‘Something is immortal if it isn’t not immortal’, and it’s entirely boneheaded. We’ve defined mortality in terms of the absence of immortality. Start sprinkling such double-negatives in Prolog — as in any representational system — and you’re very quickly lost. The mistake is right at the beginning, where we defined ‘not_immortal’. It has no place in logic programming.
Anyway, about our new dishwasher…
Apart from the program settings on our new portable dishwasher, there are two ‘options’ settings. The first, when selected, causes the dishwasher to increase the water temperature to 140 degrees before it begins to clean. It’s labelled: ‘Water Heat’. The second option is labelled:
No Heat Dry
Can you guess what it does? That’s right. When selected, it disables the application of heat at the end of the cycle to dry the dishes. I could easily talk about confusing defaults, but today I’m yakking on about logic, and I’m sure you can see how I got here. One option setting is defined in terms of the conditions under which it’s true:
water_heat :- button_1_depressed.
But the second is defined in terms of the conditions under which it’s not true:
no_heat_dry :- button_2_depressed.
There’s even a third option button labelled ‘Reset Options’, at which point things start to get mind-bending. What does it reset to? ‘No Heat Dry’? Or ‘No No Heat Dry’? (I’m guessing that the designer isn’t a Prolog programmer.) The result is a throughly confusing user interface, and a long and tedious blog entry. Blame Kenmore, not me.