prolog中的尾递归程序,计数正数和负数(Tail-recursive program in prolog which counts positive and negative numbers)

我想在prolog中写一个尾递归程序: count_neg(Ls, N, R)如果Ls是一个整数列表且N是负数元素的数量,那么这是真的。 R应代表非负面元素的列表。

一个例子:

count_neg([1,-2,0,1,2,-3],N,R). N = 2, R = 4.

这是我迄今为止编写的代码:

count_neg(Ls, N, R) :- count_neg(Ls, 0, 0, N, R). count_neg([L|Ls], Cnt1, Cnt2, N, R) :- (L > 0 -> C1 is Cnt1 + 1, !; L < 0 -> C2 is Cnt2 + 1, !), count_neg(Ls, C1, C2, N, R). count_neg([], Cnt1, Cnt2, N, R) :- N is Cnt1. count_neg([], Cnt1, Cnt2, N, R) :- R is Cnt2.

问题是, N和R在开始时都是用0初始化的,这是正确的,但是当程序应该计算第一个负数时,它不会从零开始计数,而是从_21532开始计数,并产生错误:

有没有人知道这里有什么问题? 我也想在我的程序中使用Cuts。

I want to write a tail-recursive program in prolog: count_neg(Ls, N, R) which is true if Ls is a list of integers and N is the amount of negative elements. R should represent the list of non-negative elements.

An example:

count_neg([1,-2,0,1,2,-3],N,R). N = 2, R = 4.

Here's the code I've written so far:

count_neg(Ls, N, R) :- count_neg(Ls, 0, 0, N, R). count_neg([L|Ls], Cnt1, Cnt2, N, R) :- (L > 0 -> C1 is Cnt1 + 1, !; L < 0 -> C2 is Cnt2 + 1, !), count_neg(Ls, C1, C2, N, R). count_neg([], Cnt1, Cnt2, N, R) :- N is Cnt1. count_neg([], Cnt1, Cnt2, N, R) :- R is Cnt2.

The problem is, that N and R both are initialized with 0 at the beginning which is correct, but when the program should count the first negative number it does not start counting from zero but from _21532 and results with an error:

Has anyone an idea what's wrong here? I also want to use Cuts in my program.

最满意答案

问题来自于你没有正确更新索引,并且调用谓词is/2且参数未实例化。 可能的解决方案可能是:

count_neg(Ls, N, R):- count_neg(Ls, 0, 0, N, R). count_neg([],C1,C2,C1,C2). count_neg([L|Ls], Cnt1, Cnt2, N, R):- (L > 0 -> C1 is Cnt1 + 1, C2 is Cnt2 ; C2 is Cnt2 + 1, C1 is Cnt1), count_neg(Ls, C1, C2, N, R). ?- count_neg([1,-2,0,1,2,-3,8],N,R). N = 4 R = 3

你也不需要最后两个谓词和剪辑。 在这个问题中,你说R应该代表一个列表,但是以前的解决方案你没有得到一个列表。 要获得它,你可以像这样修改程序:

countNeg(L,N,R):- countNeg(L,N,0,R,[]). countNeg([],N,N,R,R). countNeg([H|T],N,C,R,L1):- ( H < 0 -> C1 is C+1, countNeg(T,N,C1,R,L1); append(L1,[H],L2), countNeg(T,N,C,R,L2)). ?- countNeg([1,-2,0,1,2,-3],N,R). N = 2 R = [1, 0, 1, 2]

在这个解决方案中,你也可以注意到你在每个分支中调用countNeg/5 (并且我检查是否< 0 ,而在前一种情况下你检查> 0 )。

The problem comes from the fact you don't update correctly the indices and call the predicate is/2 with arguments not instantiated. A possible solution could be:

count_neg(Ls, N, R):- count_neg(Ls, 0, 0, N, R). count_neg([],C1,C2,C1,C2). count_neg([L|Ls], Cnt1, Cnt2, N, R):- (L > 0 -> C1 is Cnt1 + 1, C2 is Cnt2 ; C2 is Cnt2 + 1, C1 is Cnt1), count_neg(Ls, C1, C2, N, R). ?- count_neg([1,-2,0,1,2,-3,8],N,R). N = 4 R = 3

Also you don't need the last two predicates and the cuts. In the question you say that R should represent a list but with the previous solution you don't get a list. To obtain it, you can modify the program like this:

countNeg(L,N,R):- countNeg(L,N,0,R,[]). countNeg([],N,N,R,R). countNeg([H|T],N,C,R,L1):- ( H < 0 -> C1 is C+1, countNeg(T,N,C1,R,L1); append(L1,[H],L2), countNeg(T,N,C,R,L2)). ?- countNeg([1,-2,0,1,2,-3],N,R). N = 2 R = [1, 0, 1, 2]

In this solution you can also notice that you call countNeg/5 in each branch (and i check if < 0, while in the previous case you check > 0).

更多推荐