Prolog计数列表元素高于n

时间:2013-12-02 12:45:19

标签: prolog

我是Prolog的新手,所以我对某项任务有一些问题。任务是编写尾递归谓词count_elems(List,N,Count)条件List_Element > N, Count1 is Count+1

我的方法:

count_elems( L, N, Count ) :-
   count_elems(L,N,0).
count_elems( [H|T], N, Count ) :-
   H > N ,
   Count1 is Count+1 ,
   count_elems(T,N,Count1).
count_elems( [H|T], N, Count ) :-
   count_elems(T,N,Count).

错误-MSG:

ERROR: toplevel: Undefined procedure: count_elems/3 (DWIM could not correct goal)

我不太清楚问题出在哪里。 thx任何帮助:)

3 个答案:

答案 0 :(得分:7)

如果你想编写一个尾递归版本的代码,你需要(如CapelliC指出的那样)一个额外的参数作为累加器。您可以在第一个条款中看到问题:

count_elems(L, N, Count) :- count_elems(L,N,0).

这里,Count是一个单例变量,没有在任何地方实例化。您对count_elems的递归调用开始计入0,但不再需要使用total实例化变量。所以,你需要:

count_elems(L, N, Count) :-
    count_elems(L, N, 0, Count).

然后声明count_elem/4子句:

count_elems([H|T], N, Acc, Count) :-
    H > N,                            % count this element if it's > N
    Acc1 is Acc + 1,                  % increment the accumulator
    count_elems(T, N, Acc1, Count).   % check the rest of the list
count_elems([H|T], N, Acc, Count) :-
    H =< N,                           % don't count this element if it's <= N
    count_elems(T, N, Acc, Count).    % check rest of list (w/out incrementing acc)
count_elems([], _, Count, Count).     % At the end, instantiate total with accumulator

您还可以为count_elems/4使用“if-else”结构:

count_elems([H|T], N, Acc, Count) :-
    (H > N
    ->  Acc1 is Acc + 1
    ;   Acc1 = Acc
    ),
    count_elems(T, N, Acc1, Count).
count_elems([], _, Count, Count).

同样正如CapelliC指出的那样,您声明的错误信息可能是因为您没有阅读prolog源文件。

答案 1 :(得分:3)

使用保留

以下是:

:- use_module(library(clpfd)).

count_elems([],_,0).
count_elems([X|Xs],Z,Count) :-
   X #=< Z,
   count_elems(Xs,Z,Count).
count_elems([X|Xs],Z,Count) :-
   X #> Z,
   Count #= Count0 + 1,
   count_elems(Xs,Z,Count0).

让我们来看看多功能count_elems/3是多少:

?- count_elems([1,2,3,4,5,4,3,2],2,Count).
Count = 5 ;                                   % leaves useless choicepoint behind
false.

?- count_elems([1,2,3,4,5,4,3,2],X,3).
X = 3 ;
false.

?- count_elems([1,2,3,4,5,4,3,2],X,Count).
Count = 0, X in 5..sup ;
Count = 1, X = 4       ;
Count = 3, X = Count   ;
Count = 5, X = 2       ;
Count = 7, X = 1       ;
Count = 8, X in inf..0 .

编辑2015-05-05

我们也可以使用元谓词 tcount/3,与(#<)/2的具体化版本结合使用:

#<(X,Y,Truth) :- integer(X), integer(Y), !, ( X<Y -> Truth=true ; Truth=false ).
#<(X,Y,true)  :- X #<  Y.
#<(X,Y,false) :- X #>= Y.

让我们再次运行查询!

?- tcount(#<(2),[1,2,3,4,5,4,3,2],Count).
Count = 5.                                           % succeeds deterministically

?- tcount(#<(X),[1,2,3,4,5,4,3,2],3).
X = 3 ;
false.

?- tcount(#<(X),[1,2,3,4,5,4,3,2],Count).
Count = 8, X in inf..0 ;
Count = 7, X = 1       ;
Count = 5, X = 2       ;
Count = 3, X = Count   ;
Count = 1, X = 4       ; 
Count = 0, X in 5..sup .

关于效率的说明:

  • count_elems([1,2,3,4,5,4,3,2],2,Count)留下了无用的选择点。
  • tcount(#<(2),[1,2,3,4,5,4,3,2],Count)确定性地成功。

答案 2 :(得分:2)

好像你没有查阅你的源文件。

当您解决此问题时(可以将这些规则保存在文件count_elems.pl中,然后发出?- consult(count_elems).),您将面临Count它在第一个规则中是单身的实际问题,表示你必须将计数器传递给实际的尾递归子句,并在列表'访问完成时将它与累加器(更新为Count1的Count)统一起来。

你将以3个count_elems / 4子句结束。不要忘记基本情况:

count_elems([],_,C,C).