计算Prolog中列表中的出现次数时出错

时间:2017-05-22 09:43:37

标签: prolog

我试图在Prolog中开发一个小程序。目前,我从Prolog开始,因此有些问题我不太了解。

我的程序假装计算列表中元素的出现次数。最后,它必须显示下一条消息:"元素X出现N次。"

代码如下:

count_occur(X, [], N) :- format("Element ~d occurrs ~d times. ~n", [X,N]).
count_occur(X, [X|T], N) :- 
    count_occur(X, T, N2), 
    N is N2 + 1.    
count_occur(X, [Y|T], N) :- 
    X \= Y,          
    count_occur(X, T, N). 

咨询一个例子我总是得到以下错误:

?- count_occur(5,[2, 5, 5, 5, 6, 6, 8, 9, 9, 9], 0).
Element 5 ocurrs 
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR:   [19] format("Element ~d ocurrs ~d times. ~n",[5,_8398])
ERROR:   [18] count_occur(5,[],_8428) at /Users/serrodcal/Repositories/PLExercises1/ex1.pl:1
ERROR:   [11] count_occur(5,[5,6|...],_8456) at /Users/serrodcal/Repositories/PLExercises1/ex1.pl:3
ERROR:   [10] count_occur(5,[5,5|...],_8496) at /Users/serrodcal/Repositories/PLExercises1/ex1.pl:3
ERROR:    [9] count_occur(5,[5,5|...],0) at /Users/serrodcal/Repositories/PLExercises1/ex1.pl:3
ERROR:    [7] <user>
ERROR: 
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.

我正在使用像计数器这样的第三个参数,但在案例基础上Prolog不知道N的值。

3 个答案:

答案 0 :(得分:3)

如果您坚持打印该消息,我建议至少将输出与描述实际关系的谓词分开。考虑一下这种模式:

calling_predicate(...) :-
   other_predicate(...),   % <- predicate describing the actual relation
   format(...).            % <- output

例如,您可以将count_occur/3替换为来自@ User9213帖子的calling_predicatecount_occur_/3 other_predicate。或者,您可以选择使用@mat建议的CLP(FD)。例如,考虑使用if_/3的以下版本:

:- use_module(library(clpfd)).

count_occur(X, L, N) :-
   list_x_count_(L,X,N,0),                             % <- actual relation
   format("Element ~w occurs ~d times. ~n", [X,N]).    % <- output

list_x_count_([],_X,N,N).
list_x_count_([Y|Ys],X,N,N0) :-
   if_(Y=X,(N0 #< N, N1 #= N0+1), N1 #= N0),
   list_x_count_(Ys,X,N,N1).

由于列表中的元素不一定是数字,因此对于参数~w而不是X使用转义序列~d是恰当的(参见{{3}的文档更多细节)。如果您使用给定的示例查询,则会得到所需的结果:

?- count_occur(5,[2,5,5,5,6,6,8,9,9,9], N).
Element 5 occurs 3 times. 
N = 3.

请注意,此查询会确定性地成功。也就是说,没有多余的选择点,因此在Prolog告诉您唯一答案后,您无需输入;。 @mat和@ lambda.xy.x在评论中提供的示例查询也起作用:

?- count_occur(1,[2,X],0).
Element 1 occurs 0 times. 
dif(X, 1).

?- count_occur(a, [a,b,c], N).
Element a occurs 1 times. 
N = 1.

?- count_occur(X, [a,b,c], N).
Element a occurs 1 times. 
X = a,
N = 1 ;
Element b occurs 1 times. 
X = b,
N = 1 ;
Element c occurs 1 times. 
X = c,
N = 1 ;
Element _G210 occurs 0 times. 
N = 0,
dif(X, c),
dif(X, b),
dif(X, a).

答案 1 :(得分:2)

我不知道它是如何工作的,就像你写的那样。也许这样写:

count_occur(X, L, N) :- count_occur_(L, X, N).

count_occur_([], _, 0). % the 0 here is important (why?)
count_occur_([X|Xs], X, N) :-
    count_occur_(Xs, X, N0),
    succ(N0, N).
count_occur_([Y|Ys], X, N) :-
    dif(Y, X),
    count_occur_(Ys, X, N).

答案 2 :(得分:-1)

我发现了错误。解决方案是:

count_occur(X, [], N) :- format("Element ~d occurrs ~d times. ~n", [X,N]).
count_occur(X, [X|T], N) :- 
    N2 is N + 1,
    count_occur(X, T, N2).    
count_occur(X, [Y|T], N) :- 
    X \= Y,          
    count_occur(X, T, N).

第二次count_occur语句错误,并且没有充分递增。