Prolog from the ground up

Numbers and arithmetic with is

Working out values with is, the difference between a slash and div, and the comparisons that ask questions about numbers.

Part 3 of 12

Beginner15 min readBack to Courses

Working out a value

Arithmetic does not happen by itself inside a goal. To compute something you use is, which works out the expression on its right and makes the variable on its left stand for the result: X is 4 + 3 leaves X as 7.

The variable has to be free before that goal runs, because the answer flows to the left. Everything on the right is an expression built from numbers, the operators + and -, a few named operators, and any variable that already holds a number.

The right side follows the usual precedence: multiplication, division, div and mod bind tighter than addition and subtraction, and brackets override both. 2 + 3 * 4 is 14, while (2 + 3) * 4 is 20. Unary minus binds to the number that follows it, so -3 * 2 is -6; when in doubt, add brackets rather than rely on a table you have to remember.

Whole numbers, fractions, remainders

Division has two forms. A slash answers with a decimal, so 9 / 2 is 4.5, while the word div keeps the answer whole and mod gives the remainder: 9 div 2 is 4 and 9 mod 2 is 1. There is also rem for a remainder that keeps the sign of the number, and abs, max and min for the obvious jobs.

Comparisons are written with the signs you know: <, >, =< and >=. To compare two numbers by value you use =:=, which is why 3 =:= 3.0 is true even though a whole number and a decimal are different kinds of term.

mod and rem differ when a negative number is involved. mod takes the sign of the divisor, so -7 mod 3 is 2; rem takes the sign of the dividend, so -7 rem 3 is -1. Both obey the same rule — quotient times divisor plus remainder equals the original — but only one is the remainder you meant.

What is actually evaluated

is is the only goal here that does arithmetic. X = 2 + 3 unifies X with the term 2 + 3; it does not compute 5. X is 2 + 3 evaluates the right side and hands the answer to X. Both goals succeed and both print something, which is why the difference is easy to miss until a sum comes out as an expression.

The right side is evaluated with the operators the engine knows, and every variable on it must already hold a number. X is Y + 1 with Y free is an error, not a guess. The left side has to be free or match the result, because the answer flows that way; arithmetic does not run backwards, so 3 is X + 1 does not solve for X.

A worked comparison makes the difference plain. After X = 2 + 3, writing X prints 2+3, and X =:= 5 fails because the term is not the number. After Y is 2 + 3, Y is 5 and Y =:= 5 succeeds. = builds or matches a term; is asks the engine to calculate.

What goes wrong

The first mistake is using = where is was meant. The goal succeeds, so nothing warns you; the error appears later when a comparison treats the expression as a term. If a printed “number” looks like a sum, the binding used = instead of is.

The second is comparing with == instead of =:=. 3 == 3.0 fails because the terms differ, while 3 =:= 3.0 succeeds because the values are equal. The third is an unbound variable on the right of is, which raises an instantiation error rather than guessing a value; bind it with a previous goal first.

Values, divisions and remainders

main :-
    X is 4 + 3,
    Y is X * 2,
    write('x is '), write(X), nl,
    write('y is '), write(Y), nl,
    Half is 9 / 2,
    write('9 / 2 is '), write(Half), nl,
    Whole is 9 div 2,
    write('9 div 2 is '), write(Whole), nl,
    Left is 9 mod 2,
    write('9 mod 2 is '), write(Left), nl.
:- initialization(main).

Five lines of sums

Run it and check each line. Then change the last comparison so it prints the other sentence, and work out the first line by hand before you trust it.

Output
Click "Run" to execute your code

Three mistakes to watch for. A bare + inside a term is not addition: X = 2 + 3 leaves X as a compound term, so use is when you want a number. A single slash always gives a decimal, while div keeps the answer whole. And a comparison is a goal, not a value: X > 3 succeeds or fails, so put it inside an if-then-else when a reader should see a sentence.

Try these next

  • Work out 23 div 4 and 23 mod 4 on paper, then print both and compare.
  • Write a rule that turns a number of minutes into hours and minutes with div and mod.
  • Change one comparison in the example and predict which sentence prints before you run it.

Split a bill

Run it and check the arithmetic. Then change the bill and the number of people and predict the new answers before you run.

Output
Click "Run" to execute your code

A comparison is a goal, not a value. X > 3 succeeds or fails, and write cannot turn it into a word — put it inside an if-then-else when you want to print yes or no.

Check what you learned

One question at a time. A wrong answer explains itself — take another go.

Part 1 of 5

What does X is 4 + 3 do?