我是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任何帮助:)
答案 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)
使用logical-purity保留clpfd!
以下是:
:- 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 .
我们也可以使用元谓词
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).