I am a writing Prolog predicate that would compare some point (myPosition(2,2)
) in Cartesian coordinate system with some other point in the neighbourhood. As a result, it should show the direction (north, east, south, west) that we should choose to get from myPosition(2,2)
to that point. Here is the code of my .pl
file:
myPosition(2,2).
turn_to_east(X+1,Y) :-
myPosition(X,Y),
write('East.').
turn_to_west(X-1,Y) :-
myPosition(X,Y),
write('West.').
turn_to_north(X,Y+1) :-
myPosition(X,Y),
write('North.').
turn_to_south(X,Y-1) :-
myPosition(X,Y),
write('South.').
turn_to_the_point(X,Y) :- turn_to_east(X,Y).
turn_to_the_point(X,Y) :- turn_to_west(X,Y).
turn_to_the_point(X,Y) :- turn_to_north(X,Y).
turn_to_the_point(X,Y) :- turn_to_south(X,Y).
Then, when I upload the file to SWI-Prolog and write:
turn_to_the_point(1,2).
I get just:
false.
Why can't I get the answer 'West.' or any other?
The reason is that by default Prolog does not interpret +
, -
and other arithmetic operators. 1+1
is simply 1+1
(this is syntactical sugar for +(1,1)
), not 2. This could be useful if you for instance would like to define your own expression evaluator, and you see +
as the boolean sum, or something completely different.
There is however one way to collapse such expression such that it derives 2
out of 1+1
using the (is)/2
predicate. For instance:
turn_to_east(NX,Y) :-
myPosition(X,Y),
NX is X+1,
write('East.').
Given you query turn_to_east/2
with turn_to_east(1,2)
, NX = 1
. Now you fetch the myPosition/2
data: X = 2
and Y = 2
. Prolog does an equivalence check in the meantime and sees that the Y-coordinate of turn_to_east/2
is the same as the one of myPosition
. Next it collapses 2+1
to 3
and sees that this is not equivalent to NX = 1
so this predicate fails. But if you had queried turn_to_east(3,1)
it would have succeeded and thus write East.
.
If you modify your entire theory with the above discussed concept, like:
myPosition(2,2).
turn_to_east(NX,Y) :-
myPosition(X,Y),
NX is X+1,
write('East.').
turn_to_west(NX,Y) :-
myPosition(X,Y),
NX is X-1,
write('West.').
turn_to_north(X,NY) :-
myPosition(X,Y),
NY is Y+1,
write('North.').
turn_to_south(X,NY) :-
myPosition(X,Y),
NY is Y-1,
write('South.').
turn_to_the_point(X,Y) :- turn_to_east(X,Y).
turn_to_the_point(X,Y) :- turn_to_west(X,Y).
turn_to_the_point(X,Y) :- turn_to_north(X,Y).
turn_to_the_point(X,Y) :- turn_to_south(X,Y).
It answers the query correctly:
?- turn_to_the_point(1,2).
West.
true ;
false.
A note in general is that predicates better not have side-effects like write/1
stuff: this is not only for Prolog, almost all programming languages advice to split a program into calculation and interaction. Perhaps a better way to solve this, is to see the direction as an parameter:
myPosition(2,2).
turn_to_point(NX,Y,east) :-
myPosition(X,Y),
NX is X+1.
turn_to_point(NX,Y,west) :-
myPosition(X,Y),
NX is X-1.
turn_to_point(X,NY,north) :-
myPosition(X,Y),
NY is Y+1.
turn_to_point(X,NY,south) :-
myPosition(X,Y),
NY is Y-1.
turn_to_the_point(X,Y) :-
turn_to_point(X,Y,D),
write(D).
In that case the turn_to_the_point/2
predicate is clearly an interaction predicate whereas its turn_to_the_point/3
variant does computations.