Don't repeat solutions in Prolog

prolog, prolog-setof

Solution

I got to an answer.

% Include the dictionary
:- [p1]. % The dictionary with sons

:- dynamic(found/2).

brother(X, Y) :-
    % Get two persons from the database to test
    son(X, P),
    son(Y, P),

    % Test if the two persons are different and were not already used
    testBrother(X, Y).

% If it got here it's because there is no one else to test above, so just fail and retract all
brother(_, _) :-
    retract(found(_, _)),
    fail.

testBrother(X, Y) :-
    X \= Y,
    \+found(X, Y),
    \+found(Y, X),

    % If they were not used succed and assert what was found
    assert(found(X, Y)).

It always returns fails in the end but it succeeds with the following.

- brother(X, Y). % Every brother without repetition

- brother('Urraca', X). % Every brother of Urraca without repetition

- brother('Urraca', 'Sancho I'). % True, because Urraca and Sancho I have the same father and mother. In fact, even if they only had the same mother or the same father it would return true. A little off context but still valid, if they have three or more common parents it would still work

It fails with the following:

- brother(X, X). % False because it's the same person

- brother('Nope', X). % False because not is not even in the database

- brother('Nope', 'Sancho I'). % False, same reason

So like this I can, for example, ask: brother(X, Y), and start pressing ";" to see every brother and sister without any repetition.

I can also do brother(a, b) and brother(b, a), assuming a and b are persons in the database. This is important because some solutions would use @< to test things and like so brother(b, a) would fail.

So there it is.

Problem

Suppose you have a database with the following content: ``` son(a, d). son(b, d). son(a, c). son(b, c). ``` So a and b are sons of d and c. Now you want to know, given a bigger database, who is brother to who. A solution would be: ``` brother(X, Y) :- son(X, P), son(Y, P), X \= Y. ``` The problem with this is that if you ask "brother(X, Y)." and start pressing ";" you'll get redundant results like: - X = a, Y = b; - X = b, Y = a; - X = a, Y = b; - X = b, Y = a; I can understand why I get these results but I am looking for a way to fix this. What can I do?

Original source