Prolog how to get adjacent numbers in rule

Viewed 66

Very new to prolog, Anyways

I have a database with names,road number,address.

habite('Name', Num, 'Address').

I want to create a rule voisins(X,Y) which returns the names of people with the same address as Y but with Num being either Num or it's adjacents(Num+1) and (Num-1).

I tried doing the following

voisins(X,Y) :-
    habite(X,Num,Address),
    ANum is Num+1,
    habite(Y,ANum,Address);
    BNum is Num-1,
    habite(Y,BNum,Address).

and also tried

voisins(X,Y) :-
    habite(X,Num,Address),
    ANum is Num+1,
    BNum is Num-1,
    habite(Y,ANum,Address),
    habite(Y,ANum,Address).

They both don't work. I feel like this has a very simple answer but I'm very new to Prolog so I don't really know it . Appreciate any help.

1 Answers

You can try the following:

voisins(X,Y) :-
  habite(Y,YNum,Address),
  habite(X,XNum,Address),
  (XNum =:= YNum ; XNum =:= YNum - 1 ; XNum =:= YNum + 1).

The first goal finds the road number and address of person with name Y, which are then unified to the variables YNum and Address, respectively. The second goal then unifies the variable X with a name of a person that has the same address as Y, while additionally unifying XNum with this person's road number. Lastly, XNum is compared to YNum, in order to see if it satisfies the constraints you've mentioned at the beginning. This is expressed through disjunction: (;)/2.

Basically, Prolog will try to see if XNum has the same (arithmetic) value as YNum. If this check succeeds, then the predicate voisins(X,Y) is true for the name that got unified to X, so it answers it back to you and continues searching for other answers by doing backtracking. On the other hand, if it fails, it will move on to the next one and check whether that one holds, etc.

Equivalently, you could also write the above predicate as:

voisins(X,Y) :-
  habite(Y,YNum,Address),
  habite(X,YNum,Address).
voisins(X,Y) :-
  habite(Y,YNum,Address),
  habite(X,XNum,Address),
  XNum =:= YNum - 1.
voisins(X,Y) :-
  habite(Y,YNum,Address),
  habite(X,XNum,Address),
  XNum =:= YNum + 1.

Here, the disjunction has been "unfolded" into three separate definitions of voisins, where each does one of the three comparisons. The way it works is similar to the previous solution, only now Prolog will choose the next available predicate as an alternative, in case that a comparison fails. Also, notice how the XNum =:= YNum check is expressed more compactly, since the value YNum is used in habite(X,YNum,Address)to further constrain the possible values for X.

Related