5.2 A Closer Look
That’s the basics, but we need to know more. The most important to grasp is this: +, *, -, ÷ 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 unified the variable X to the complex term 3+2 . It has not carried out any arithmetic. It has simply done what it usually does when =/2 is used: 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 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 built-in 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 a 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 a variable-free arithmetic expression. 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. This is because arithmetic isn’t performed using Prolog’s 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, it’s 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 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) really 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 go to the right of is , and to take care that any variables are correctly instantiated. But there is a deeper point that is worth reflecting on: bolting on the extra capability to do arithmetic in this way has further widened the gap between the procedural and declarative meanings of Prolog programs.