Search code examples
prologinstantiation-error

Prolog count numbers of elements Error


I'm learning prolog, and I want to count a specific element occurence in a list.

So here is the code -

count(_, [], _) := !.

count(El, [El|T], N) :-
    N1 is N + 1,
    count(El, T, N1).

count(El, [_|T], N) :-
    count(El, T, N).

check(List1, List2) :-
    count(3, List1, M),
    count(2, List2, N),
    M is N.

so basically I would like to pass to console check([3,4,3], [2,3,4,5,2]), and it should return true, because occurences of 3 in list1 is the same as occurences of 2 in list2. But instead it throws me -

Arguments are not sufficiently instantiated. 
Exception: (10) _G1383 is _L155+1 ? creep
Exception: (9) count(3, [3, 4, 2], _G1385) ? creep
Exception: (8) count(3, [2, 3, 4, 2], _G1385) ? creep
Exception: (7) check([2, 3, 4, 2], [2, 3, 4]) ? creep 

What is the cause of this, and how can I solve it? I checked all around forum, and everywhere it's written that this should work. Is this some kind of version related stuff, or really I'm missing here something?

EDIT: Using SWI-Prolog.

EDIT2:

Got it working, thank you!

Code:

count(_, [], 0) :- !.

count(El, [El|T], N) :-
    count(El, T, N1),
    N #= N1 + 1.

count(El, [Y|T], N) :-
    El \= Y,
    count(El, T, N).

check(List1, List2) :-
    count(3, List1, M),
    count(2, List2, N),
    M #= N.

Solution

  • You are using predicates that are called moded because they can only be used in very specific situations. In particular, (is)/2 cannot be used as a relation as you need it here.

    One way to solve this is to use more general predicates instead. For example, when reasoning over integers, consider using your Prolog system's CLP(FD) constraints, which work in all directions.

    For example, with GNU Prolog, you can make the error go away if you simply replace (is)/2 by (#=)/2:

    count(_, [], _).
    
    count(El, [El|T], N) :-
        N1 #= N + 1,
        count(El, T, N1).
    
    count(El, [_|T], N) :-
        count(El, T, N).
    
    check(List1, List2) :-
        count(3, List1, M),
        count(2, List2, N),
        M #= N.
    

    Now we get:

    ?- count(3, [3, 4, 2], C).
    C+1#=_1204 ;
    true ;
    false.
    

    (or, depending on your Prolog system, an equivalent answer).

    Why? Obviously, the program is a bit flawed.

    I leave finding the mistake as an exercise. Hint: M #= N looks suspicious: This is true iff M is equal to N...