【问题标题】:Tail-recursive program in prolog which counts positive and negative numbersprolog中的尾递归程序,计算正数和负数
【发布时间】:2023-12-28 09:05:01
【问题描述】:

我想在 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.

问题是,NR 都在开头初始化为 0,这是正确的,但是当程序应该计算第一个负数时,它不是从零开始计数,而是从 _21532 开始计数,结果为一个错误:

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

【问题讨论】:

  • 为什么全部删减?

标签: prolog tail-recursion


【解决方案1】:

问题在于您没有正确更新索引并使用未实例化的参数调用谓词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(我检查是否为&lt; 0,而在前一种情况下,您检查的是&gt; 0)。

【讨论】: