1

我正在尝试创建一个规则来计算给定列表中某个元素的出现次数,到目前为止我尝试过的似乎并没有按照我期望的方式工作:

这里的第一个参数应该是列表,第二个参数是我们要查找的元素,最后一个参数是出现次数:

%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).

H是给定列表的头部尾部T

例如,基本情况按预期count([],1,N).返回N = 0,但只要列表非空,我们总是会得到false.

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

谁能指出我做错了什么?

更新:

将第二行替换为

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

但我就是不明白为什么这不等于我的第一个想法。

然后我们得到

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

哪个是对的。

4

2 回答 2

4

评估与统一

在 Prolog=/2中是一个统一运算符。它不会将术语作为表达式进行评估,即使该术语可能代表数值上可评估的东西。同样,当您使用 时count([E|T], E, N+1),Prolog不会评估术语N+1。对于 Prolog,这只是另一个术语,内部表示为+(N, 1).

对于要作为数字表达式解释和评估的术语,您需要使用特定的 Prolog 运算符来执行此操作。正如@SQB 指出的那样,其中之一是is/2

N = 1, N1 is N + 1.

这将导致N1 = 2. 然而这:

N = 1, N1 = N + 1.

将导致:(N1 = 1 + 1或等效地,N1 = +(1, 1))。

Prolog 中也有数值比较运算符,它们也将计算表达式。它们是=:=/2>/2>=/2</2=</2因此,您将看到以下内容:

1 + 2 =:= 3.

将产生“真”,因为=:=/2专门用于比较可评估数值表达式的相等性。然而:

1 + 2 = 3.

将产生“假”,因为该术语与该术语+(1,2)不匹配(或更准确地说,不能与之统一)3

啊!参数没有充分实例化!

我在 SO 上看到了很多关于他们的论点“没有充分实例化”的错误的帖子。其中许多是在使用is/2. 如上所述,is/2将评估第二个参数中的表达式,然后将该结果与第一个参数统一。第二个参数必须是完全可计算的(表达式中涉及的所有变量都必须用数值​​实例化)否则你会得到一个错误。同样,在使用表达式比较时,两个参数中的所有变量都必须完全实例化。因此,如果X是一个未绑定的变量,以下将产生“参数没有充分实例化”错误:

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)

在对表达式执行约束逻辑时,要使用的工具是 CLP(FD) 库。因此:

X * 3 #= 6.

将产生,X = 2

于 2016-05-27T12:33:25.983 回答
1

问题是N+1(or N-1) 没有被评估,正如您的第二个(工作)示例所见。

% 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实际上计算方程,而不是在你的下一次调用中将与统一起来。这就是为什么在您的第二个示例中,您最终得到而不是.NN-1N=0+1+1N=2

于 2016-05-27T12:24:54.883 回答