Prolog - 递归调用

时间:2012-08-19 22:33:38

标签: list recursion prolog

我在列表的递归搜索和结果列表的创建方面遇到了麻烦。

知识库包含团队名称,胜利数量和所在区域,所有这些都与他们的团队编号相关联。我正在Teams中传递团队号码列表,我正在搜索与findMinMax/3匹配的一对。我需要的结果是......

配对团队列表清单(例如X = [[gonzaga, washington], [iowa, oklahoma], …]) 1个无与伦比的团队(由奇数队产生)或0(如果是偶数)

我想出了其他一切,可以到达[gonzaga, washington]部分,但在递归部分失败......

findPair(Teams,[HL|TL],Rest) :-
    findMinMax(Teams,Min,Max),
    delete(Teams,Min,TeamsNoMin),
    delete(TeamsNoMin,Max,Rest),
    createPair(Min,Max,Pair), %Pair = "["Min_team","Max_team"]"
    append(HL,[Pair],TL),
    findPair(Rest,TL,[]).

1 个答案:

答案 0 :(得分:6)

一般递归方案

在这里,我将向您展示我们通常如何在Prolog中执行递归。获得初学者并不简单,因为列表是“向后”构建的:在我们到达列表末尾之前,没有任何内容真正构建。

这种“向后构建”原则的原因是,一旦设置了变量,就无法将其设置为其他值,因此例如很难说结果为[1]递归的第一步然后变为[1, 2]。相反,我们在Prolog中所说的是结果头是1并且结果尾部是递归调用的结果(如果它变得混乱,则读取它两次:d)。因此,只要我们没有遇到基本情况(没有执行递归的情况),我们就不会明确地绑定变量(即我们总是让部分术语解除绑定)。

对于通过将其元素与rec/2: rec(Input, Result)相关联而从输入列表生成结果列表的谓词somepredicate/2,我们写道:

rec([InputHead|InputTail], [ResultHead|ResultTail]) :-
    somepredicate(InputHead, ResultHead),
    rec(InputTail, ResultTail).

代表那个。

在这里你可以看到我们声明结果的头部是ResultHead并且由于调用rec(InputTail, ResultTail).

而计算了它的尾部

现在这很好但是我们需要在某些时候停止,例如,当列表为空时。我们写的如下:

rec([], []).

表示:当输入列表为空时,结果列表也是如此。

谓词的应用程序

现在,要解决您的问题,首先必须修复递归子句:

findPair(Teams,[HL|TL],Rest) :-
    findMinMax(Teams,Min,Max),
    delete(Teams,Min,TeamsNoMin),
    delete(TeamsNoMin,Max,Rest),
    createPair(Min,Max,Pair), %Pair = "["Min_team","Max_team"]"
    append(HL,[Pair],TL),
    findPair(Rest,TL,[]).

会变成

findPair(Teams, [Pair|Tail], LeftOver) :-
    findMinMax(Teams, Min, Max),
    delete(Teams, Min, TeamsNoMin),
    delete(TeamsNoMin, Max, Rest),
    createPair(Min, Max, Pair), %Pair = "["Min_team","Max_team"]"
    findPair(Rest, Tail, LeftOver).

需要注意的重要事项:现在Rest已成为两个独立的变量。 findPair/3的最后一个参数不再被更改,因为在递归调用中我们还不知道它,所以我们不能绑定它,因此in-predicate Rest因此现在是独立的,只代表尚未处理的团队,因此对我们的结果列表(以及LeftOver)的尾部感兴趣。

现在我们必须处理基本情况:

  • 当没有球队离开时

    findPair([], [], []).
    

    我们说,当Teams为空时,ResultLeftOver也是如此。

  • 当有一支球队离开时

    findPair([Last], [], [Last]).
    

    我们说,当Teams只有一个元素时,LeftOver等于TeamsResult为空。

结果代码是:

findPair([], [], []).
findPair([Last], [], [Last]).
findPair(Teams, [Pair|Tail], LeftOver) :-
    findMinMax(Teams, Min, Max),
    delete(Teams, Min, TeamsNoMin),
    delete(TeamsNoMin, Max, Rest),
    createPair(Min, Max, Pair), %Pair = "["Min_team","Max_team"]"
    findPair(Rest, Tail, LeftOver).

要使您的子句独占,您可以将Teams替换为[Not, Empty|AtAll],以确保最后一个子句仅用于长度为2或更长的列表,或者只添加Teams = [_, _|_],等保护在条款的开头。

希望它有所帮助,并毫不犹豫地在评论中要求澄清:)