4

我正在尝试计算一个元素在列表中出现的次数,到目前为止我已经想出了

rate(X,[H|T],N):-
  X == H,
  N is N+1,
  rate(X,T,N).
rate(X,[_|T],N) :-
  rate(X,T,N).  
rate(_,[],N) :-
  N is 0.

我已经介绍了何时找到匹配项、何时没有匹配项以及何时到达列表末尾。但是当我测试时我得到

43 ?- rate(4,[4,2,3,4,4,2],X).
ERROR: is/2: Arguments are not sufficiently instantiated
Exception: (6) frequency(4, [4, 2, 3, 4, 4, 2], _G393) ?     

我到底错过了什么论点?

4

3 回答 3

4

当且仅当 X 是数字时,您可以使用is/2(如 in )。如果 X 是自由变量,N is X则不能使用。is/2在您的第一个子句中,您有N is N+1:这很糟糕,因为 N 是一个自由变量(此时它没有值,N+1 也是如此)。

还有一个错误。在:

rate(X,[_|T],N) :-
  rate(X,T,N).

因为只有当 X 不是列表中的第一个元素时才使用它,所以您应该检查它是否为真!这是代码:

count(_, [], 0) :- !. /* empty list, base case */

count(X, [X|T], N) :- /* if X is in the head of the list */
    count(X, T, N2), /* count on the tail (let this N2) */
    N is N2 + 1.     /* and N is N2 + 1  */

count(X, [Y|T], N) :- 
    X \= Y,          /* if X is not in the head */
    count(X, T, N).  /* just count the rest */
于 2012-08-12T16:42:51.610 回答
2

您需要使您的子句互斥,第二个子句将在第一个子句的任何地方成功。

至于你的错误,它是关于信息流的。您需要像这样交换第一个子句中的行:

rate(X,[H|T],N):-
  X == H,
  rate(X,T,N1),
  N is N1+1.

此更改将使您的谓词不是尾递归。要成为尾递归,它需要将信息传递调用链中,而不是像现在这样在向上的过程中接收它:

rate(X,[H|T],N):-
  X == H,
  N1 is N+1,
  rate(X,T,N1).

现在您看到您没有在此处收到最终值,而是指定了初始值。当我们达到基本情况时,我们得到了结果:

rate(X, [], N).

N是结果。怎么找回来?当我们到达底部时,使用附加参数,一个未实例化的变量,与这个结果统一:

rate(X, [], N, V) :- V is N.

现在递归子句必须适应这个变量,将其沿调用链原封不动地传递。

于 2012-08-12T16:42:42.953 回答
1

如果你喜欢函数式风格,你可以用 SWI Prolog 来写:

:- use_module(library(lambda)).


rate(X,L,N) :-
    foldl(\Y^V0^V1^((X = Y->V1 is V0+1; V1 = V0)), L, 0, N).
于 2012-08-14T14:36:36.763 回答