Prolog - 递归家谱

时间:2009-12-10 00:44:05

标签: prolog tree

我正在尝试编写一个Prolog程序,该程序将依次打印出英国版的男性继承人。到目前为止我的尝试:

son(elizabeth, charles).
son(charles, william).
son(charles, henry).
son(elizabeth, andrew).
son(elizabeth, edward).
son(edward, severn).
successor(X, Y) :- son(X, Y).
successor(X, Y) :- son(X, C), successor(C, Y).

后继功能并不能完全符合我的要求:当前输出为:

successor(elizabeth, Y).
Y = charles ;
Y = andrew ;
Y = edward ;
Y = william ;
Y = henry ;
Y = severn ;
false.

第一条规则将所有三个直接子项打印出来,然后第二条规则打印出所有后代。但是第一个孩子的后代应该来到第二个直系孩子之前,如下:

successor(elizabeth, Y).
Y = charles ;
Y = william ; % william and henry should come before andrew
Y = henry ;
Y = andrew ;
Y = edward ;
Y = severn ;
false.

这是我的第一个Prolog计划,我对如何表达正确的关系感到茫然。任何人都可以给我一个想法或指向对我有帮助的资源吗?

3 个答案:

答案 0 :(得分:5)

正如rati所述,Prolog查询通过选择规则,使用depth-first search递归评估它,然后选择下一个规则并重复该过程来解决。但是,您开始使用的特定规则实际上会导致系列树的breadth-first search,如您所述,它不会提供与实际连续行匹配的输出。相反,你想要对王室树进行深度优先遍历。此版本提供您正在寻找的结果:

successor(X, Y) :- son(X, Z), (Y = Z; successor(Z, Y)).

使用此规则,Prolog大致按如下方式解析查询successor(X, Y)

  • 对于Z的儿子的每个X
    • Y绑定到Z,将Z作为解决方案。
    • ;运算符用作逻辑OR,因此现在Y未绑定,并且递归调用successor/2以获取Z的儿子的继任者。

是的,请尝试获取Prolog艺术的副本。这不是最容易阅读的编程书籍,但我发现它对我(正在)理解逻辑编程的尝试非常有帮助。似乎有一些廉价精装本的1994年版本在eBay附近浮动。

答案 1 :(得分:3)

你说:

  

第一条规则会打印出所有三个直接孩子,然后第二条规则打印出所有后代。

对于任何给定的谓词(例如successor/2),PROLOG通常会按顺序评估第1个子句的所有可能解决方案,然后是下一个,等等到最后一个子句。因此,PROLOG将完全按照您的建议行事 - 首先会找到对直系子项的解法,因为successor/2的第一个子句就是这样,第二个子句找到了后代。如果您使用的是其他订单,请尝试重新订购这些条款(即。);

successor(X, Y) :- son(X, C), successor(C, Y).
successor(X, Y) :- son(X, Y).

这将导致PROLOG评估为:

?- successor(elizabeth, Y).
Y = william ;
Y = henry ;
Y = severn ;
Y = charles ;
Y = andrew ;
Y = edward.

即所有直系儿童之前的血统。

然而,通过对这些子目标进行简单的重新排序,无法实现您想要的顺序。相反,请考虑各种树遍历方法;即,有序,预订和后订购。您可以编写一个(简单)程序,它能够以各种不同的方式遍历树结构,而不是PROLOG的默认评估顺序。例如,请考虑以下successor/2的新定义:

successor(Parent, [Son|SonDescendents]) :-
    son(Parent, Son),
    successor(Son, SonDescendents).

本条款旨在深度优先填充儿子的子列表,并将回溯以找到所有解决方案。

successor(NonParent, []) :-
    \+ son(NonParent, _).

这个下一个子句处理基本情况,即给定的个体没有任何儿子,因此没有后代进入结果列表(空)。

评估这个给出:

?- successor(elizabeth, S).
S = [charles, william] ;
S = [charles, henry] ;
S = [andrew] ;
S = [edward, severn] ;
false.

PS。我强烈推荐以下用于学习PROLOG的文本:

The Art of Prolog, by Leon Sterling and Ehud Shapiro

The Craft of Prolog, by Richard O'Keefe

Programming in Prolog, by Clocksin and Mellish

答案 2 :(得分:1)

你的规则集对我来说很好,它给你正确的结果,它只是打印它们推断它们,这使得订单看起来不正确。在纸上完成结果,您可能会得到类似的结果。