Counting occurrences in list

雨燕双飞 提交于 2019-12-11 10:55:35

问题


I'm trying to create a rule that counts the number of occurrences of a certain element in a given list, what I've tried so far does not seem to work the way I expect:

The first argument here should be the list, the second one the element we are looking for, and the last one the number of occurrences:

%empty list should always return 0 occurences
count([],E,0) :- true.

%if our head is what we are looking for, count
count([E|T],E,N) :- count(T,E,N-1).

%otherwise, do not count
count([H|T],E,N) :- H \== E, count(T,E,N).

Here H is the head and T the tail of the given list.

The base case e.g. count([],1,N). returns N = 0 as expected, but as soon as the list is non empty, we always get false.:

?- count([1],1,N).
false.
?- count([1,2,1,3],1,N).
false.

Can anyone point out what I'm doing wrong?

Update:

It seems to work when replacing the second line with

count([E|T],E,N+1) :- count(T,E,N).

But I just cannot figure out why this is not equivalent to my first idea.

Then we get

?- count([1,2,1,3],1,N).
N = 0+1+1 

which is correct.


回答1:


The problem is that N+1 (or N-1) isn't evaluated, as can be seen by your second (working) example.

% empty list has 0 occurrences
count([], _, 0).

% if our head is what we are looking for, count
count([E|T], E, N) :-
    N_1 is N - 1,         % this is the important one
    count(T, E, N_1).

% otherwise, do not count
count([H|T], E, N) :-
    H \== E,
    count(T, E, N).

is actually evaluates the equation, instead of unifying the N in your next call with N-1. That's why in your second example, you end up with N=0+1+1 instead of N=2.




回答2:


Evaluation versus Unification

In Prolog =/2 is a unification operator. It does not evaluate a term as an expression even if the term might represent something numerically evaluable. Similarly, when you use count([E|T], E, N+1), Prolog does not evaluate the term N+1. To Prolog, that's just another term, which internally is represented as +(N, 1).

For a term to be interpreted and evaluated as a numeric expression, you need to use specific Prolog operators that will do that. As @SQB points out, one of these is is/2:

N = 1, N1 is N + 1.

This will result in N1 = 2. However this:

N = 1, N1 = N + 1.

Will result in: N1 = 1 + 1 (or equivalently, N1 = +(1, 1)).

There are also numeric comparison operators in Prolog that will also compute expressions. These are =:=/2, >/2, >=/2, </2 and =</2. So you will see the following:

1 + 2 =:= 3.

Will yield "true" since =:=/2 is specifically for comparing equality of evaluable numeric expressions. However:

1 + 2 = 3.

Will yield "false" because the term +(1,2) does not match (or more accurately, cannot be unified with) the term 3.

Argh! Arguments not sufficiently instantiated!

I've seen quite a few posts on SO regarding an error that their arguments are "not sufficiently instantiated". Many of these are in the use of is/2. As described above, is/2 will evaluate the expression in the 2nd argument and then unify that result with the first argument. The 2nd argument must be fully evaluable (all variables involved in the expression must be instantiated with a numeric value) or you'll get an error. Likewise, when using the expression comparisons, all of the variables in both arguments must be fully instantiated. Thus, if X is a variable that is unbound, the following will yield an "arguments not sufficiently instantiated" error:

9 is X * 3.       % Will NOT yield X = 3, but will give an error
Y + 2 =:= X * 2.  % Error if either X or Y are not instantiated
Y = 1, X = 2, Y + 2 =:= X * 2.  % Yields "false" (fails) since 3 is not equal to 4
Y = 1, X = 2, Y + 2 < X * 2.    % Yields "true" (succeeds) since 3 is less than 4
Y = 1, X = 2, X + 1 = Y + 2.    % Yields "false" since +(2,1) doesn't unify with +(1,2)

When performing constraint logic on expressions, the tool to use is the CLP(FD) library. Thus:

X * 3 #= 6.

Will yield, X = 2.



来源:https://stackoverflow.com/questions/37481942/counting-occurrences-in-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!