Zach Blocker
Zach Blocker

Reputation: 329

Prolog predicate where two items are associated but not equivalent

I haven't programmed in Prolog for years and am struggling with a simple block of test code (I'm trying to solve a logic puzzle for fun...):

aboard(jack, blackbird).
aboard(jim, blackbird).
aboard(donna, blackbird).
aboard(david, north_star).
aboard(sandy, north_star).

shipmates(A, B) :- A \= B, aboard(A, X), aboard(B, X).

shipmates1(A, A) :- !, fail.
shipmates1(A, B) :- aboard(A, X), aboard(B, X).

The shipmates and shipmates1 rules are two different attempts to accomplish the following: I want to pair all passengers who are on the same ship but are not equivalent to each other.

For example, I want shipmates(jack, jack). to be false.

When I query this with fully-qualified arguments, I get the expected answers:

3 ?- shipmates(jack, david).
false.

4 ?- shipmates(jack, jack).
false.

5 ?- shipmates(jack, jim).
true.

However, when I want all of Donna's shipmates, it doesn't seem to work:

6 ?- shipmates(donna, X).
false.

I was expecting:

X = jack ;
X = jim ;

NOTE: I get the same wrong results with shipmates1.

So please take pity on a very amateur Prolog programmer (who is not doing homework for a class!) What very obvious thing am I doing wrong?

Version: SWI-Prolog (threaded, 64 bits, version 8.0.2)

Upvotes: 1

Views: 205

Answers (1)

Paulo Moura
Paulo Moura

Reputation: 18683

Try:

shipmates(A, B) :-
    aboard(A, X),
    aboard(B, X),
    A \= B.

By calling the aboard/2 predicate before the A \= B goal, you ensure that both A and B will be instantiated, thus making the comparison meaningful.

Upvotes: 1

Related Questions