检查Prolog中的隐式规则谓词

时间:2013-08-11 19:44:43

标签: recursion prolog predicate

我希望我使用了一个可以理解的标题。我想要实现的是确定关系的序言,即使它没有明确说明。

brother(anders, jason).
sister(anders, madonna).
siblings(X,Y) :- sister(X,Y).
siblings(X,Y) :- brother(X,Y).
siblings(X,Y) :- siblings(X,Z), siblings(Z,Y).

这是我正在努力的兄弟规则。显然杰森是安德斯的兄弟,麦当娜是安德斯的妹妹。杰森和麦当娜就是安德斯的兄弟姐妹。即使没有明确说明,他们也是兄弟姐妹。如何通过检查兄弟姐妹的兄弟姐妹来确定这一点?这是我的最后一条规则会导致堆栈溢出\ o /这真的不是一个惊喜。这是以递归的方式实现的还是我需要编写更多的规则,如:

siblings(X,Y) :- sister(X,Z), brother(Z,Y).
siblings(X,Y) :- sister(X,Z), sister(Z,Y).
siblings(X,Y) :- brother(X,Z), sister(Z,Y).
siblings(X,Y) :- brother(X,Z), brother(Z,Y).

如果我们有一个非常大的家庭,甚至在我们的兄弟/姐妹事实中存在更大的差距,上述情况将无效,这可能意味着我必须检查一个人是否与兄弟姐妹同胞兄弟姐妹等等。

这可能不是一个好的现实世界的例子,但我正在寻找处理这些情况的概念,而不是解决特定问题。

2 个答案:

答案 0 :(得分:2)

在给定适当注释的情况下,它可能会自动在Prolog中使用表格(YAP或XB),但我们大多数人都生活在标准prolog Prolog的限制之内。你的附加规则实际上就是把食物推到你的盘子里。你可以看到你需要更多它们来处理这样的情况:

brother(anders, brian).
brother(celeste, donal).
sister(brian, celeste).

如果您希望sibling(anders, X)donal统一X,那么您将需要更大的船。

我们称之为递归规则:

siblings(X,Y) :- siblings(X,Z), siblings(Z,Y).

这不可能成功,因为要取得成功,首先必须成功。堆栈溢出没有发生,因为你正在递归地调用siblings/2,它正在发生,因为它调用它两次来实现它。它花了两美元来赚一个。但是,你可以通过用以下内容替换该规则来实现收支平衡:

siblings(X, Z) :- brother(X, Y), siblings(Y, Z).
siblings(X, Z) :- sister(X, Y),  siblings(Y, Z).

这是一项资本改善,但还不够。这基本上让我们指导兄弟姐妹。布莱恩是安德斯的兄弟,但安德斯不是布莱恩的兄弟。这个问题非常严重,我们永远不会承认安德斯和唐纳的兄弟情谊。我们可以通过添加更多规则来解决这个问题:

siblings(X, Y) :- brother(X, Y) ; brother(Y, Z).
siblings(X, Y) :- sister(X, Y)  ; sister(Y, X).

这些规则使得兄弟情谊和姐妹情谊无法实现。现在你得到了你想要的所有结果:

?- siblings(anders,Y).
Y = brian ;
Y = anders ;
Y = celeste ;
Y = donal ;
Y = brian ;
Y = celeste ;
false.
打赌你可以弄清楚如何消除自我兄弟问题。其他重复可能会变得更麻烦。试一试,如果你遇到困难,请告诉我们。

答案 1 :(得分:1)

你想要的transitive closure

sibl(A,B):- brother(A,B) ; brother(B,A) ; sister(A,B) ; sister(B,A).

sibl_trans(A,B):- sibl(A,B).
sibl_trans(A,B):- sibl(A,C), sibl_trans(C,B).

您的定义就像

sibl_trans(A,B):- sibl(A,B).
sibl_trans(A,B):- sibl_trans(A,C), sibl_trans(C,B).

这是left recursion。用depth-first search的Prolog来表示不好。 可以使用iterative deepening

这个问题经常出现。