我父亲的侄子在prolog

Eri*_*dia 3 logic prolog

我在prolog中编程一个家庭,我在使用nephew实现时遇到了麻烦.当我问埃里克是否是阿尔贝托的侄子时,它返回真实,因为它应该返回假,因为阿尔贝托是埃里克的父亲,然而,它确实适用于所有其他应该是真实的情况.如果有人能帮助我,我将非常感激.我的代码:

man(beto).
man(fransisco).
man(alberto).
man(jaime).
man(manolo).
man(nolo).
man(lito).
man(manuel).
man(erick).
man(jesu).
man(jesus).
woman(emi).
woman(harumi).
woman(haru).
woman(yuneisi).
woman(yasmeli).
woman(mioara).
woman(elia).
woman(iza).
woman(alice).
woman(ofelia).
woman(arlet).
parent(manuel, alberto).
parent(ofelia, alberto).
parent(manuel, jaime).
parent(ofelia, jaime).
parent(manuel, manolo).
parent(ofelia, manolo).
parent(alberto, erick).
parent(alberto, beto).
parent(alberto, fransisco).
parent(emi, erick).
parent(emi, beto).
parent(manolo, nolo).
parent(manolo, arlet).
parent(nolo, lito).
parent(iza, lito).
parent(mioara, yuneisi).
parent(mioara, yasmeli).
parent(jaime, yuneisi).
parent(jaime, yasmeli).
parent(jesus_padre, jesu)
parent(jesus_padre, alice).
parent(jesus_padre, haru).
parent(harumi, haru).
parent(harumi, jesu).
parent(harumi, alice).
father(X,Y) :- parent(X,Y), man(X).
mother(X,Y) :- parent(X,Y), woman(X).
brother(X,Y) :- man(X), parent(F, X), parent(F, Y).
sister(X,Y) :- woman(X), parent(P, X), parent(P, Y).
grandpa(X,Y) :- father(F,Y), father(X,F), man(X).
grandma(X,Y) :- father(F,Y), mother(X,F), woman(X).
son(X,Y) :- father(Y,X), man(X).
nephew(X,Y) :- father(F,X), brother(F,Y).
Run Code Online (Sandbox Code Playgroud)

tas*_*tas 5

除了parent(jesus_padre, jesu)@LuaiGhunim所指出的缺失点之外,你的谓词还有一些其他问题.你对兄弟/ 2的定义过于笼统.没有人是他自己的兄弟,但如果你查询你的谓词,你会发现几个这样的例子:

?- brother(X,X).
X = beto ;
X = beto ;
X = fransisco ;
X = alberto ;
X = alberto ;
X = jaime ;
X = jaime ;
X = manolo ;
X = manolo ;
X = nolo ;
X = lito ;
X = lito ;
X = erick ;
X = erick ;
X = jesu ;
X = jesu ;
false.
Run Code Online (Sandbox Code Playgroud)

您可以通过添加目标dif/2来轻松解决此问题:

brother(X,Y) :-
   dif(X,Y),
   man(X),
   parent(F, X),
   parent(F, Y).
Run Code Online (Sandbox Code Playgroud)

现在上面的查询失败了,因为它应该:

?- brother(X,X).
false.
Run Code Online (Sandbox Code Playgroud)

你还会得到很多对两次:

?- brother(X,Y).
X = beto,               % <- 1st occurrence
Y = erick ;             % <- 1st occurrence
X = beto,
Y = fransisco ;
X = beto,               % <- 2nd occurrence
Y = erick ;             % <- 2nd occurrence
.
.
.
Run Code Online (Sandbox Code Playgroud)

原因是你可以通过母亲或父亲来获得它.在上面的示例(betoerick)中,您将通过emi或来到那里alberto.这些解决方案可能是多余的,但它们是正确的 您的谓词妹妹/ 2也是如此:

?- sister(X,X).
X = haru ;
X = haru ;
X = yuneisi ;
X = yuneisi ;
X = yasmeli ;
X = yasmeli ;
X = alice ;
X = alice ;
X = arlet.
Run Code Online (Sandbox Code Playgroud)

补救措施与上述相同:

sister(X,Y) :-
   dif(X,Y),
   woman(X),
   parent(P, X),
   parent(P, Y).

?- sister(X,X).
false.

?- sister(X,Y).
X = haru,
Y = jesu ;
X = haru,
Y = alice ;
X = haru,
Y = jesu ;
.
.
.
Run Code Online (Sandbox Code Playgroud)

另一方面,您对grandma/2和grandpa/2的定义过于具体.要查看此内容,请在代码中添加以下事实:

man(m1).
man(m2).

woman(w1).
woman(w2).
woman(w3).

parent(m1,w1).
parent(w1,w2).
parent(w2,w3).
Run Code Online (Sandbox Code Playgroud)

然后,以下查询应该成功,但它们会失败:

?- grandpa(m1,w2).
false.

?- grandma(w1,w3).
false.
Run Code Online (Sandbox Code Playgroud)

原因是爷爷/ 2和祖母/ 2的定义中的中间父亲是父/ 2,它应该是父/ 2.此外,最后的目标(man(X)woman(X))是多余的,因为它们已分别由父/ 2和母/ 2覆盖.相反,您可以像这样定义两个谓词:

grandpa(X,Y) :-
   parent(F,Y),
   father(X,F).

grandma(X,Y) :-
   parent(F,Y),
   mother(X,F).
Run Code Online (Sandbox Code Playgroud)

现在上面的查询产生了所需的结果:

?- grandpa(m1,w2).
true.

?- grandma(w1,w3).
true.
Run Code Online (Sandbox Code Playgroud)

最后,根据剑桥词典的侄子是你的姐妹或兄弟的儿子,或你的丈夫或妻子的姐妹或兄弟的儿子.既然你没有丈夫和妻子的谓词,我会坚持你的姐姐或兄弟一个儿子.如果您为丈夫和妻子添加事实,您可以添加其他规则以涵盖定义的其他部分.您可以在Prolog中编写定义的第一部分,如下所示:

nephew(X,Y) :-
   man(X),
   dif(F,Y),
   parent(P,F),
   parent(P,Y),
   parent(F,X).
Run Code Online (Sandbox Code Playgroud)

如果您查询此谓词,则不再有erick/alberto解决方案:

?- nephew(erick,X).
X = jaime ;
X = manolo ;
X = jaime ;
X = manolo ;
false.
Run Code Online (Sandbox Code Playgroud)

  • @CapelliC:我同意学习目标排序是至关重要的.但是它的某些方面比其他方面更容易掌握.我发现直观易于理解的一个方面是,某些目标可能会比其他目标更加缩小搜索空间,并且将这些目标放在第一位可能会导致更快的谓词.然而,知道目标是通过连接连接而且连接是可交换的,我发现A&B&C可能产生与B&C&A不同的结果是非常违反直觉.这就是为什么我认为对于初学者来说,dif/2可能更容易. (4认同)
  • @CapelliC:我认为dif/2比替代品更容易使用,特别是对于新用户.考虑以下查询:`? - A\= B`产生`false`,而`? - dif(A,B).`产生`dif(A,B).`,即约束传播.因此`? - A\= B,A = a,B = b.产生`假.但是`? - A = a,B = b,A\= B`成功,`A = a,B = b.`.另一方面`? - A = a,B = b,dif(A,B).`和`? - dif(A,B),A = a,B = b.两者都产生`A = a, B = b.因此,有必要确保...... (3认同)
  • @CapelliC:......包含\ =/2的目标在它的两个参数都被接地之后被发布,因为即使`? - A = a,A\= B,B = b.产生`false.这可能导致新用户很难找到的错误.我很清楚在所有Prolog实现中都没有dif/2,但它有很多.我当然不反对使用标准的内置插件,我只是发现dif/2更容易/更优雅的选择所以我建议:-) (2认同)
  • @tas:"导致更快的谓词" - 至少首先放置始终终止目标不会恶化终止属性.也就是说,要么它们保持不变,要么变得更好.速度,这一切都取决于 (2认同)