需要帮助了解Prolog中的某些事情

时间:2011-04-28 09:58:04

标签: prolog

我是Prolog的初学者,并且发现在使用规则时很难理解回溯是如何工作的。我甚至不知道回溯是否适用于规则(想要正确地了解它)。

我有以下程序,它将列表中的所有偶数整数相加。我自己写了,但发现很难理解找到解决方案所需的步骤。

evenN(X):- (X mod 2) =:= 0.

sumEven([], 0).
sumEven([H|T], X):- evenN(H), sumEven(T,Y), X is Y+H.
sumEven([H|T], X):- \+evenN(H), sumEven(T,X).

输出:::

?- sumEven([1,2,3,4,5,6],X).
X = 12

需要帮助才能更好地理解它。我尝试使用跟踪实用程序来理解输出,但我不理解它,这就是为什么我在这里问。

问题:

1)

当我注释掉第二条规则(最后一行)时,它会给我一个失败作为答案,因为1不是偶数,整个sumEven()失败,因为偶然N()失败,我理解。我的问题是:事后会发生什么?它会回到顶部并尝试sumEven([],0)事实还是?我只是想知道会发生什么。

2)

当包含最后一行(第二个规则),并且第一个规则失败时,当它回溯时,它是否会查找其后的另一个sumEven()(就像第二个规则遵循失败的第一个规则的方式)或它回到顶部并测试sumEven([],0)事实并从那里开始它?

我需要了解在prolog中使用规则时它是如何回溯的,特别是在像这样的递归情况下。

3) 我在网上找到了以下代码(递归)。它将列表分为正面和负面列表。

% predicates
    split(list,list,list)

% clauses
    split([],[],[]).
    split([X|L],[X|L1],L2):-
        X>= 0,
        !,    
        split(L,L1,L2).

    split([X|L],L1,[X|L2]):-
        split(L,L1,L2).

Output :        

Goal: split([1,2,-3,4,-5,2],X,Y)

X=[1,2,4,2], Y=[-3,-5]

有人可以帮我理解找到解决方案的方法吗?我的意思是我想逐步了解它如何执行以提出解决方案。

2 个答案:

答案 0 :(得分:3)

匹配子句按照它们在程序中出现的顺序进行尝试。在很好的声明性Prolog程序中,子句的顺序不会改变程序的含义。这接近于逻辑,其中析取是可交换的。 sumEven / 2有这个属性。然而,它被错误地命名,因为总和是关系的第二个参数,而不是它的第一个参数。一个更好的名字就是例如even_sum / 2,你可能会想出更好的名字。 split / 3使用!/ 0,它会破坏此属性并让子句的顺序重要。出于这个原因,本地if-then-else(( - >)/ 2和(;)/ 2)似乎更适合这种情况。而不是trace / 0,使用SWI-Prolog的图形跟踪器?- gtrace, your_goal.,它还会向您显示哪些选项仍有待尝试。一般来说,从关系的角度思考并问:这个条款什么时候举行?如果...等等,这就可以解释更大的程序,其中确切的执行流程可能更难理解。

答案 1 :(得分:2)

看看你是否可以获得Ivan Bratko的“人工智能Prolog编程”。

他解释了Prolog遵循的过程,以便很好地满足目标。

我会尝试单独回答你的问题:

clause 1: evenN(X):- (X mod 2) =:= 0.
clause 2: sumEven([], 0).
clause 3: sumEven([H|T], X):- evenN(H), sumEven(T,Y), X is Y+H.
clause 4: sumEven([H|T], X):- \+evenN(H), sumEven(T,X).

问题:

1)当我注释掉第二条规则(最后一行)时,它会给我一个失败作为答案,因为1不是偶数,整个sumEven()失败,因为偶然N()失败,我理解。我的问题是:事后会发生什么?它会回到顶部并尝试sumEven([],0)事实还是?我只是想知道会发生什么。

A:你评论出来的条款4. Prolog试图满足目标,首先尝试第2条,因为列表不为空而失败,然后尝试第3条,但是规则失败H为奇数时为1。现在它将尝试在第3节中找到另一个子句(它不会回溯到第3节之前的那个),因为你将它注释掉后会失败,因此目标失败。

2)当包含最后一行(第二个规则),并且第一个规则失败时,当它回溯时,它是否会查找其后的另一个sumEven()(就像第二个规则遵循第一个规则失败的方式一样) )或者它回到顶部并测试sumEven([],0)事实并从那里开始它?

A:当第3条失败时,它不会回溯,但会继续执行下一条(4)。

我需要了解在prolog中使用规则时它是如何回溯的,特别是在像这样的递归情况下。

A :如果规则evenN(H)成功,sumEven(T,Y)将使用T和Y从第2节再次启动整个过程。如果sumEven(T,Y)失败由于某种原因,第三节将失败并且Prolog回溯并尝试第4条。如果当前调用是sumEven([2,3,...],X)和sumEven([3,...],Y)失败出于某种原因,Prolog会回溯并尝试在第3条之后找到另一个条款sumEven([2,3,...],X)。

3)我在网上发现了以下代码(递归)。它将列表分为正面和负面列表。

clause 1:    split([],[],[]).
clause 2:    split([X|L],[X|L1],L2):- X>= 0, !, split(L,L1,L2).
clause 3:    split([X|L],L1,[X|L2]):- split(L,L1,L2).

有人可以帮我理解找到解决方案的方法吗?我的意思是我想逐步了解它如何执行以提出解决方案。

A :我将使用较短的目标分割(numlist,PosList,NegList)和numlist = [1,-1,2,-2]。非常粗略地说它的工作原理如下(它实际上使用一个堆栈来放置匹配的值,并且只有在它展开这个堆栈时它的目标最终成功时才实例化变量 - 请参阅Bratko的书以获得更精细的细节):

第1条失败,因为numlist不为空。

第2条适用于:split([1 | -1,2,-2],[1 | L1],[Y | L2]) - 因为1> = 0 PosList现在为[1],和split将应用于numlist = [ - 1,2,-2]的尾部。

第1条再次失败。第2条适用于分割([ - 1 | 2,-2],[ - 1 | L1],[Y | L2]) - 它失败,因为-1 <1。 0,Prolog将应用第3条分割([ - 1 | 2,-2],[1],[ - 1 | L2] - NegList现在将为[-1],并再次拆分将应用于尾部numlist = [2,-2]。

第1条失败;第2节成功,PosList变为[1,2],分割应用于numlist = [ - 2]。

第1条及第1条2失败;第3节成功,NegList成为[-1,-2]。 numlist的尾部为空,第1个子句成功,返回PosList = [1,2]和NegList [-1,-2]。

相关问题