More departures from logic

Up: Traveller
Back: to main list of student notes

## More departures from logic

At the end of the skiing example in Supplement 1, I talked about the importance of writing mutually exclusive rules and showed two that aren't:

The problem with non mutually-exclusive rules is that they are logically inconsistent, since they state that two inconsistent things are both true. Logically, if the skier above could do a maximum of 13 pressups, he would have to be of both poor and good fitness!

Similarly, in COLLIER,

the third rule, taken logically, states that ``For all N, if the collier is at N, his act must be a move to the next clockwise square M''. This is inconsistent with the preceding rules which say that sometimes the act must be to buy or sell.

So why does this work? The reason is that, as mentioned at the end of Lesson 5, Prolog works through the clauses from the top down, and chooses the first one that succeeds. It may later backtrack and look for another solution, as it did with `loves(X,Y)` in

`      loves(X,Y), Y \= mary.`
If this were to happen in either of the knowledge bases above, it would indeed produce two mutually inconsistent solutions: a fitness that's both good and poor, or an act that's both a move and a buy (or sell).

This doesn't matter in Traveller, because I have written the program surrounding `act` so that it swallows the first solution `act` yields up, and does not backtrack and ask for any others. Hence you can get away with mutually inconsistent rules, as long as you remember that they are tested from the top down, the first solution coming from the first clause to succeed. I have written all the examples used with the Tutor so that this is true.

However, you should be aware that this is a departure from logic, and that we're using Prolog's execution order to resolve inconsistencies. This will become obvious if you load COLLIER, move the third clause to the top, and then call `run`.

There are various ways around the problem of inconsistencies. The purest approach is always to write conditions in full. Were we to do so with COLLIER, the third rule would become

Here I have used `not` (mentioned briefly in the animals classifier of Supplement 4) to negate the first two conditions. This approach is logically good because the third rule now carries with it all the information it needs, and no longer has to rely on its position relative to the others. It makes the program easier to read, because a reader can understand the third rule in isolation, without having to examine the preceding ones.

Unfortunately, writing all conditions in full can result in very long-winded programs, and in inefficiencies. This is because Prolog has to test some conditions more than once. An alternative approach is to use a special symbol called cut and written as an exclamation mark:

Textbooks often make a great fuss about the cut, trying to give the impression that it is rather more complex than, say, quantum mechanics, or the justification for monetarism (the first is false; the second may well be true). In this context though, there's no mystery. The cut tells Prolog ``when you have got here, do not consider any alternative solutions''. So the first cut is saying, in effect, ``if buy was one solution, sell and move are completely ruled out''.

You can test cut's effect by setting up `collier`'s load and position (using `at` and `carries`) so that he is at a retailer with a load to sell. Then ask the question

`    act( collier, Act, Arg1, Arg2 ).`
and reply `y` every time Prolog asks whether you want another solution. Without the cuts, you will get two solutions, a `sell` and a `move`. With them, only one.

This is one of cut's two uses; in the other, it's inserted between goals to stop the earlier one backtracking. I shall say no more about cut until the final lesson. In the meantime, I may write rules that look inconsistent, but I will rely on any predicates that call them never to ask for more than one solution. You may do the same ...but you should know when you are doing it.

When I return to the cut, I shall present it as a kind of internal ``if'', which can be used in writing predicates that perform one action or another depending on the result of a condition. This will be a fiction, but a benign one: as long as you follow the programming style I recommend, no problems will arise.