5.2 A closer look

That's the basics, but we need to know more. The most important to grasp is this: +, *, -, \div and mod do not carry out any arithmetic. In fact, expressions such as 3+2, 3-2 and 3*2 are simply terms. The functors of these terms are +, - and * respectively, and the arguments are 3 and 2. Apart from the fact that the functors go between their arguments (instead of in front of them) these are ordinary Prolog terms, and unless we do something special, Prolog will not actually do any arithmetic. In particular, if we pose the query

?- X = 3+2

we don't get back the answer X=5. Instead we get back

X = 3+2
yes

That is, Prolog has simply bound the variable X to the complex term 3+2. It has not carried out any arithmetic. It has simply done what it usually does: performed unification Similarly, if we pose the query

?- 3+2*5 = X

we get the response

X = 3+2*5  
yes

Again, Prolog has simply bound the variable X to the complex term 3+2*5. It did not evaluate this expression to 13. To force Prolog to actually evaluate arithmetic expressions we have to use

is

just as we did in our in our earlier examples. In fact, is does something very special: it sends a signal to Prolog that says `Hey! Don't treat this expression as an ordinary complex term! Call up your inbuilt arithmetic capabilities and carry out the calculations!'

In short, is forces Prolog to act in an unusual way. Normally Prolog is quite happy just unifying variables to structures: that's its job, after all. Arithmetic is something extra that has been bolted on to the basic Prolog engine because it is useful. Unsurprisingly, there are some restrictions on this extra ability, and we need to know what they are.

For a start, the arithmetic expressions to be evaluated must be on the right hand side of is. In our earlier examples we carefully posed the query

?- X is 6+2.
 
X = 8 

which is the right way to do it. If instead we had asked

6+2 is X.

we would have got an error message saying instantiation_error, or something similar.

Moreover, although we are free to use variables on the right hand side of is, when we actually carry out evaluation, the variable must already have been instantiated to an integer. If the variable is uninstantiated, or if it is instantiated to something other than an integer, we will get some sort of instantiation_error message. And this makes perfect sense. Arithmetic isn't performed using Prolog usual unification and knowledge base search mechanisms: it's done by calling up a special `black box' which knows about integer arithmetic. If we hand the black box the wrong kind of data, naturally its going to complain.

Here's an example. Recall our `add 3 and double it' predicate.

add_3_and_double(X,Y) :- Y is (X+3)*2.

When we described this predicate, we carefully said that it added 3 to its first argument, doubled the result, and returned the answer in its second argument. For example, add_3_and_double(3,X) returns X = 12. We didn't say anything about using this predicate in the reverse direction. For example, we might hope that posing the query

add_3_and_double(X,12).

would return the answer X=3. But it doesn't! Instead we get the instantiation_error message. Why? Well, when we pose the query this way round, we are asking Prolog to evaluate 12 is (X+3)*2, which it can't do as X is not instantiated.

Two final remarks. As we've already mentioned, for Prolog 3 + 2 is just a term. In fact, for Prolog, it really is the term +(3,2). The expression 3 + 2 is just a user-friendly notation that's nicer for us to use. This means that if you really want to, you can give Prolog queries like

X is +(3,2)

and Prolog will correctly reply

X = 5

Actually, you can even given Prolog the query

is(X,+(3,2))

and Prolog will respond

X = 5

This is because, for Prolog, the expression X is +(3,2) is the term is(X,+(3,2)). The expression X is +(3,2) is just user friendly notation. Underneath, as always, Prolog is just working away with terms.

Summing up, arithmetic in Prolog is easy to use. Pretty much all you have to remember is to use is to force evaluation, that stuff to be evaluated must goes to the right of is, and to take care that any variables are correctly instantiated. But there is a deeper lesson that is worth reflecting on. By `bolting on' the extra capability to do arithmetic we have further widened the distance between the procedural and declarative interpretation of Prolog processing.


Patrick Blackburn, Johan Bos and Kristina Striegnitz
Version 1.2.5 (20030212)