涉及算术运算和计数元素的列表上的递归



我正在努力真正掌握对Prolog列表和递归调用的理解。我一直在开发一个程序来跟踪有多少项目大于列表的头部,然后递归调用此关系以检查大于下一个元素,依此类推。我已经让我的程序工作到可以计算大于头部的元素数量,但是一旦它到达终点并尝试递归调用下一个元素的关系,它就会失败。根据我所做的研究,以下是我所拥有的以及我认为它应该如何工作:

Input - List = [7,2,4,3,6,9,8,10,12,5].
testHead(List).
testHead([H|T]) :-
greaterThan(H,T,0),
teastHead(T).

^我的理解是这种关系从列表中获取 head 元素,并使用 head 和列表的其余部分调用大于。在 greaterThan 完成后,它应该递归调用 testHead(T) 来测试下一个元素,依此类推。

greaterThan(H,[X|T],C) :-
H > X ->
C2 is C+1,
greaterThan(H,T,C2);
greaterThan(H,T,C).

^我的理解是 head 元素中的大于读取、列表的其余部分以及用于计数的变量。如果头部大于下一个元素,则增加计数并使用尾部和新计数递归调用大于;否则递归调用大于而不增加计数。

我的预期输出将是C2 = 12.(7大于 5 个元素,2大于0个元素,4大于1个元素,依此类推)

当前的实际输出是5;然后false.
我的程序似乎正确地计算和递增了头部元素,但是当它完成该元素的大于时,程序返回 false。我尝试研究和理解prolog中的列表和递归调用,但我一直碰壁。我不确定它是否失败,因为您无法递归运行增量关系,或者我的列表关系是否存在其他问题。任何关于如何解决这个问题以及prolog如何在这里发挥作用的澄清都会有所帮助。

让我们从你的第一个代码片段开始:

testHead(List).  
testHead([H|T]) :-
greaterThan(H,T,0),
teastHead(T).

你有递归的想法,但我看到四个问题。

第一testHead只有一个属性,这意味着(除了truefalse)你什么也得不到。所以它应该看起来更像这样:testHead([H|T], L) ....

第二:你需要知道什么时候停止。这通常是谓词的第一行。你的状态:任何东西都匹配。但它应该这样说:如果没有剩余的元素,我可以"返回"一个空列表。testHead([],[]).

第三:使用固定值调用greaterThan(H,T,0)0,这意味着您要测试"输出"值是否为零。事实并非如此,你想数东西。所以在这里放一个变量:N

第四:如果你计算了一个值N你必须把它转发到输出列表。由于您将从递归调用中获取列表Nlist,因此您可以创建一个新列表,其中N作为 head 元素,Nlist作为尾部元素并"返回"这个新列表。

结论:

testHead([],[]).
testHead([H|T],[N|Nlist]) :-
greaterThan(H,T,N),
testHead(T,Nlist).

可悲的是我们还不能测试它,我们必须看看greaterThan/3. 您的代码段如下:

greaterThan(H,[X|T],C) :-
H > X ->
C2 is C+1,
greaterThan(H,T,C2);
greaterThan(H,T,C).

还有一些部分很奇怪。

首先:你需要告诉何时停止。通常,您会以空列表[]停止,或者如果列表只剩下一个元素[A]。如果您对A的内容不感兴趣,请使用以下划线_开头的"丢弃变量"。这将导致:greaterThan(_,[],0).这意味着:如果我的列表为空,则无论引用值是多少,我的列表中都有 0 个大数字。另外,由于规则的顺序很重要,因此您将其放在递归规则之上。

第二:你做对了大小写,所以如果H大于列表的头部X某事,否则"忽略"X,只调用同一个谓词而不X。问题出现在something部分:由于C2的值在C之前是统一的,因此您需要根据C2计算C,反之亦然。C is C2+1的意思是:我知道递归调用C2的值,从H>X开始,我想在其值中添加一个值并"返回"它。

第三:你刚问greaterThan(H,T,C2)就知道C2的价值,所以把C is C2+1放在后面。

好的,现在我们得到了:

greaterThan(_,[],0).
greaterThan(H,[X|T],C) :-
H > X ->
greaterThan(H,T,C2),
C is C2+1;
greaterThan(H,T,C).
testHead([],[]).
testHead([H|T],[N|Nlist]) :-
greaterThan(H,T,N),
testHead(T,Nlist).

让我们测试一下!

?- testHead( [7,2,4,3,6,9,8,10,12,5],L).
L = [5, 0, 1, 0, 1, 2, 1, 1, 1, 0] ;
false.

看起来不错,除了你不想要一个列表,而是一个总数。好的,你来了:

testHead([],0).
testHead([H|T],New) :-
greaterThan(H,T,N),
testHead(T,NN),
New is NN+N.
?- testHead( [7,2,4,3,6,9,8,10,12,5],N).
N = 12 ;
false.

说明:如果你的输入列表是空的,没有什么可做的,"返回"中性元素进行加法:0.
如果你的输入列表有一个头元素H,通过greaterThan(H,T,N)计算"大于剩余元素N"。假设您的代码有效,以便您可以T为尾列表调用testHead(T,NN)并获取NN的总和值。如果值NNN都已知,则将它们相加并将其声明为"返回"。

最新更新