Search code examples
duplicatesprologswi-prolognon-interactive

Why does Prolog duplicate all the answers when the number of print directives is more than one?


Following is my knowledge base:

parent(claudia, taiane).
parent(wl, cris).
parent(cris, jim).
parent(cris, pedro).

man(jim).
man(pedro).
man(w).
man(wl).

woman(taiane).
woman(claudia).
woman(cris).

When my main has just one print:

main:-

  man(M),
  print(M), nl, 
  fail.
main:- halt.

when I execute it with swipl -q -s exercise-family-tree.pl -g main I get nonduplicated results (all good). On the other hand, when I query more in my main and have print two times with two different variables as its arguments in my main:

main:-
  %which women have both a father and a son in the database?
  woman(X), parent(X, S), parent(F, X), man(F), man(S), print(X), nl, 
  man(M),
  print(M), nl, 
  fail.
main:- halt.

than the results get duplicated. Why does my code duplicate all the answers in the second case?

The issue is different from the one I raised earlier. Please let any interactive solutions that involve REPL be outside of the scope of this question.


Solution

  • than the results get duplicated. Why does my code duplicate all the answers in the second case?

    I don't think your problem is anything to do with the top level or way you're running it from the command line, it's that you don't really understand Prolog search, choice points and backtracking and have written a nested loop which prints the same results twice.

    The first code acts like (pseudocode):

    for M in [jim, pedro, w, wl]:
        print(M)
    

    The second code acts like a nested loop:

    for _Child in [jim, pedro]:
        print(chris)          % NB: same 'chris' 
                              %   for both choices of _Child
        for M in [jim, pedro, w, wl]:
            print(M)
    

    In more detail, the first code with man(M), print(M), nl, fail runs like this:

    man(jim),   print(jim),   fail,  % backtrack to man(M)
    man(pedro), print(pedro), fail,  % backtrack to man(M)
    man(w),     print(w),     fail,  % backtrack to man(M)
    man(wl),    print(wl),    fail.  % backtrack to man(M)
    % no more man(M) choices
    

    The second case, this code:

    woman(X), parent(X, S), parent(F, X), man(F), man(S), print(X), nl, 
    man(M),
    print(M), nl, 
    fail.
    

    runs like this:

    woman(taiane),  parent(taiane,  ???)  % implicit fail
    woman(claudia), parent(claudia, ???)  % implicit fail
    woman(chris),parent(chris, jim),parent(wl, chris),man(wl),man(jim),print(chris)
    %                          ~~~
    % found a solution, now go forward through the man(M) code:
    
        man(jim),   print(jim),   fail,  % backtrack to man(M)
        man(pedro), print(pedro), fail,  % backtrack to man(M)
        man(w),     print(w),     fail,  % backtrack to man(M)
        man(wl),    print(wl),    fail,  % backtrack to man(M)
    
        % no more man(M) choices, now the last choicepoint was 
        % at parent(chris, S) which had choice S=jim or S=pedro.
        % Redo that:
    
    woman(chris),parent(chris, pedro),parent(wl, chris),man(wl),man(jim),print(chris)
    %                          ~~~~~
    % found a solution, now go forward through the man(M) code:
    
        man(jim),   print(jim),   fail,  % backtrack to man(M)
        man(pedro), print(pedro), fail,  % backtrack to man(M)
        man(w),     print(w),     fail,  % backtrack to man(M)
        man(wl),    print(wl),    fail.  % backtrack to man(M)
    
        % no more man(M) choices, now parent(chris, S) has
        % no more choices, so end.
    

    So you make two different choices for S from [jim,pedro] by X=chris, parent(X, S) but do not report them, and only report the other choices, for X and M, which are the same in both cases, so it looks like duplication.