我正在努力真正掌握对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
只有一个属性,这意味着(除了true
和false
)你什么也得不到。所以它应该看起来更像这样: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
的总和值。如果值N
和NN
都已知,则将它们相加并将其声明为"返回"。