我希望我使用了一个可以理解的标题。我想要实现的是确定关系的序言,即使它没有明确说明。
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).
如果我们有一个非常大的家庭,甚至在我们的兄弟/姐妹事实中存在更大的差距,上述情况将无效,这可能意味着我必须检查一个人是否与兄弟姐妹同胞兄弟姐妹等等。
这可能不是一个好的现实世界的例子,但我正在寻找处理这些情况的概念,而不是解决特定问题。
答案 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。
这个问题经常出现。