【问题标题】:Prolog Recursion - Satisfying Both Directions (Simple)Prolog 递归 - 满足两个方向(简单)
【发布时间】:2016-03-31 21:32:33
【问题描述】:

我是 Prolog 的新手,我被分配了这个任务。

我的代码如下:

relatives(cindy,tanya).
relatives(tanya,alan).
relatives(alan,mike).
relatives(kerry,jay).
relatives(jay,alan).

isRelated(X,Y):-
    relatives(X,Y).
isRelated(X,Y):-
    relatives(X,Z),
    isRelated(Z,Y).

足够简单。这表明如果:

?- isRelated(cindy,mike).

Prolog 将返回 true。现在,如果:

?- isRelated(mike,cindy).

我一直在尝试想出一些想法,比如如果 isRelated(Z,Y) 返回 false,然后切换 X 和 Y,然后再次运行 isRelated。但我不确定 Prolog 是否允许这样的想法。任何提示或建议将不胜感激。谢谢!

更新:************************************

所以我补充说:

isRelated(X,Y):-
    relatives(X,Y);
    relatives(Y,X).

这将满足“直接”关系,但很简单,我发现它不满足间接关系。

我真的想做一些类似的事情,如果初始查询:

isRelated(mike,cindy)

失败,然后通过切换X和Y尝试看看是否相反:

isRelated(cindy,mike)

那肯定会返回 true。我只是不知道如何在 Prolog 的语法上做到这一点。

【问题讨论】:

  • 提示问题:如果relatives(Y,X) 成立,XY 是否相关?
  • 是的,这是为了家庭作业。我绝对不是这个网站的新手,所以我知道不要寻求可能会给出太多答案的具体建议。我已经用 C/Java 编程 2 年了,但我最近才开始使用 Prolog。这绝对是一种完全不同的动物。
  • 我在您的问题中添加了“作业”标签,这就是我问的原因。 :) 祝你驯服 Prolog 好运,尤其是。推荐“序言的艺术”。当您到达差异列表时,请跳过所有炒作,只需记住:它只是开放式列表,结束指针明确保留在手边,因此可以在需要时进行设置。也可以将 logvars 视为命名指针,它只能设置一次(在回溯之前)。干杯。

标签: recursion prolog transitive-closure


【解决方案1】:

进一步提示 cmets 中的人,因为我还不能离开 cmets:根据您原来的规则和事实, isRelated(cindy,tanya) 是真的,但isRelated(tanya,cindy) 不是,所以你需要使isRelated(X,Y) 对称;对isRelated 进行什么简单的补充可以实现这一目标?

另外,您可以尝试绘制关系图relatives(X,Y),并为您的所有基本事实使用从 X 到 Y 的箭头,看看这是否有助于您考虑 Prolog 解释器将如何尝试满足查询。

【讨论】:

  • 嗯,我喜欢这个主意。但我有个问题。假设查询是: isRelated(cindy,tanya) 返回 true。那么这是否意味着 Prolog 现在退出了整个代码呢?因为我知道在 Java/C++ 中,返回和布尔值(无论是真还是假)都会完全退出函数。不知道Prolog中是不是同样的情况。
  • @user1227566 你通常会在一些 Prolog 提示符下运行 Prolog 查询。假设它是 SWI-Prolog'?- ,然后你输入isRelated(tom,jerry).,按回车,它会向你吐出一些答案。 Prolog 在这一点上被暂停。它停在了中间,它知道它现在在哪里。现在您可以按点. 停止,或按; 再尝试一次,它将从暂停点继续。如果还有其他答案,它也会显示给您;等等。如果没有,它会说No。然后搜索就完全结束了。
  • 哦,难怪我在查询后总是要按两次回车。我不知道 Prolog。
  • 是的,按 Enter 键是在告诉 Prolog 系统:“谢谢,我对我想要的很满意。不要再搜索了”。 (而且按点根本不起作用,不知道我在想什么)。
  • @Jason 我尝试添加一个适用于直接关系的简单代码,但它不适用于间接关系。我编辑了我的原始帖子。
【解决方案2】:

所以要回答你的最后一个问题,你不要在 Prolog 中切换 XY,就像在 C 中调用 swap(x,y) 一样。逻辑变量持有的值不能显式更改,只能回溯。但是你可以很容易地使用Y,而你会使用X,反之亦然:

somePred(X,Y):- is_it(X,Y).
somePred(X,Y):- is_it(Y,X).

这将somePred 谓词定义为一个逻辑析取,一个“OR”。也可以显式地写出来,比如

somePred(X,Y):- is_it(X,Y) ; is_it(Y,X).

注意那里的分号。谓词 OTOH 之间的逗号 , 定义了一个连词,即 "AND"(复合词中的逗号仅用于分隔该词的“参数”)。

【讨论】:

    【解决方案3】:

    你快到了,我想你只是想把太多东西塞进一个谓词中。

    用英语写出问题陈述并以此为基础:

    两个人 X 和 Y 之间存在关系

    • 如果 X 和 Y 直接相关,或者
    • 如果 X、P 的任何直系亲属与 Y 相关。

    然后就简单了。我会这样处理它:

    首先,您有一组关于亲戚的事实。

    related( cindy, tanya ).
    ...
    related( james, alan ).
    

    那么,描述直接关系的谓词就是这些事实的术语:

    directly_related( X , Y ) :- % a direct relationship exists 
      related(X,Y)               %   if X is related to Y
      .                          % ... OR ...
    directly_related( X , Y ) :- % a direct relationship exists
      related(Y,X)               %   if Y is related to X
      .                          %
    

    最后,一个描述任何关系的谓词:

    is_related(X,Y) :-        % a relationship exists between X and Y
      directly_related(X,Y)   %   if a direct relationship exists between them
      .                       % ... OR ...
    is_related(X,Y) :-        % a relationship exists between X and Y
      directly_related(X,P) , %   if a direct relationship exists between X and some other person P
      is_related(P,Y)         %   and [recursively] a relationship exists between P and Y.
      .                       %
    

    解决方案实际上比这更复杂:

    1. 关于关系的事实描述了一个或多个graphs。有关图表的更多信息,请访问 http://web.cecs.pdx.edu/~sheard/course/Cs163/Doc/Graphs.html。您正在做的是在图中找到从节点 X 到节点 Y 的路径。

    2. 如果关于关系的事实所描述的图表在 X 和 Y 之间有一条或多条路径,则上述解决方案可以(并且将会)成功多次(在回溯时),每条路径一次。解决方案需要确定性。通常,在确定两个人有亲属关系后,我们就完成了:仅仅因为我有两个堂兄弟并不意味着我与我的姑姑有两次亲属关系。

    3. 1234563这意味着解决方案需要检测和处理周期。如何实现?

    【讨论】:

      猜你喜欢
      • 2013-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多