Prolog: why my predicate returns false?

前端 未结 2 1150
日久生厌
日久生厌 2021-01-16 07:33

so I wrote a predicate that counts how many times an element occurs in a list of lists.

count([], _, 0).                                  #base case

count([         


        
相关标签:
2条回答
  • 2021-01-16 08:16

    Ok, it looks like it was backtracking on the part where 'Elem is not the head of sublist', and I was able to fix it by changing it to:

    count([[_|Rest]|OtherLists], Elem, Count) :-      #Elem is not the head of sublist
        !,
        count([Rest|OtherLists], Elem, Count).
    

    If anyone can confirm whether this is a correct solution. Thanks

    0 讨论(0)
  • When Prolog encounters a "choice point" (a place in the code where it can come back to seek more possible solutions) in the process of finding a solution, it will show the solution and prompt you for more possible solutions. If it finds no more, it displays "false". This is not any kind of error in your logic. It's the way Prolog works.

    It is not always desirable to remove the choice point. It depends upon what your goals are for the predicate. The danger in removing choice points using cuts is that the choice point may be a path to valid alternative solutions, and the cut prevents your program from finding those solutions.

    Let's try your updated program with the new proposed cut in your answer:

    | ?- count([[1,2,3],[4,1,5],[4,6,1]], 1, X).
    
    X = 3
    
    yes
    | ?- count([[1,2,1,3],[4,1,5],[4,6,1]], 1, X).
    
    X = 4
    
    yes
    | ?- count([[1,2,1,3],[4,1,5],[4,6,1],[1]], 1, X).
    
    X = 5
    

    So far, so good. These look like complete and correct answers. I believe your additional cut (and including your original cut) will yield a correct answer as long as the first argument is fully bound with no variables. Let's try a more interesting query:

    2 ?- count([[A,2,B],[C,1,D]], 1, X).
    A = B, B = C, C = D, D = 1,
    X = 5.
    
    3 ?-
    

    The predicate found one solution. However, aren't there more? What about this one?

    A = _ % something other than 1
    B = C, C = D, D = 1,
    X = 4.
    

    This would be a correct solution as well, but the predicate fails to find it.

    Also, what about this query?

    2 ?- count([[1,2,1,3],[4,1,5],[4,6,1],[1]], E, X).
    E = 1,
    X = 5.
    
    3 ?-
    

    Again, only one solution found. But aren't there more? What about E = 4 and X = 2?

    If we remove all of the cuts from the original predicate in an attempt to get all of the correct solutions, then we get incorrect solutions as well:

    2 ?- count([[1,2],[3,1,4],[1]], 1,X).
    X = 3 ;
    X = 2 ;
    X = 2 ;
    X = 1 ;
    X = 2 ;
    X = 1 ;
    X = 1 ;
    X = 0 ;
    false.
    2 ?- count([[1,2,1,3],[4,1,5],[4,6,1],[1]], E, X).
    E = 1,
    X = 5 ;
    E = 1,
    X = 4 ;
    E = 1,
    X = 3 ;
    ...
    

    So if more generality is desired, a more effective solution needs to be constructed.

    count_occurrences_lol([], _, 0).
    count_occurrences_lol([List|Lists], X, Count) :-
        count_occurrences(List, X, C1),        % Count occurrences in this list
        count_occurrences_lol(Lists, X, C2),   % Count occurrences in remaining sublists
        Count is C1 + C2.                       % Total the counts
    
    count_occurrences([], _, 0).
    count_occurrences([X|Xs], X, Count) :-
        count_occurrences(Xs, X, C1),
        Count is C1 + 1.
    count_occurrences([X1|Xs], X, Count) :-
        dif(X1, X),
        count_occurrences(Xs, X, Count).
    

    Now we get the following:

    3 ?- count_occurrences_lol([[1,2],[3,1,4],[1]], 1,X).
    X = 3 ;
    false.
    

    Just one solution, as expected. And the following:

    5 ?- count_occurrences_lol([[A,2,B],[C,1,3]], 1, X).
    A = B, B = C, C = 1,
    X = 4 ;
    A = B, B = 1,
    X = 3,
    dif(C, 1) ;
    A = C, C = 1,
    X = 3,
    dif(B, 1) ;
    A = 1,
    X = 2,
    dif(B, 1),
    dif(C, 1) ;
    B = C, C = 1,
    X = 3,
    dif(A, 1) ;
    B = 1,
    X = 2,
    dif(A, 1),
    dif(C, 1) ;
    C = 1,
    X = 2,
    dif(A, 1),
    dif(B, 1) ;
    X = 1,
    dif(A, 1),
    dif(B, 1),
    dif(C, 1) ;
    false.
    
    3 ?- count_occurrences_lol([[1,2,1,3],[4,1,5],[4,6,1],[1]], E, X).
    E = 1,
    X = 5 ;
    E = 2,
    X = 1 ;
    E = 3,
    X = 1 ;
    E = 4,
    X = 2 ;
    E = 5,
    X = 1 ;
    E = 6,
    X = 1 ;
    X = 0,
    dif(E, 1),
    dif(E, 1),
    dif(E, 6),
    dif(E, 4),
    dif(E, 5),
    dif(E, 1),
    dif(E, 4),
    dif(E, 3),
    dif(E, 1),
    dif(E, 2),
    dif(E, 1).
    
    4 ?-
    

    Several possible solutions as expected.

    0 讨论(0)
提交回复
热议问题