prolog中的递归引用

prolog中的递归引用,prolog,transitive-closure,Prolog,Transitive Closure,我在尝试实施时遇到了一些问题 friends(mia, ellen). friends(mia, lucy). friends(X,Y) :- friends(X,Z), friends(Y,Z). 当我问?-friends(mia,X)。时,它的本地堆栈就用完了 然后我加上 friends(ellen, mia) friends(lucy, mia) 我问?-朋友(mia,X)。,它一直在回答X=mia 我不明白,为什么它是递归的?朋友/2的这一条款有缺陷: friends(X,

我在尝试实施时遇到了一些问题

friends(mia, ellen).
friends(mia, lucy).
friends(X,Y) :-
  friends(X,Z),
  friends(Y,Z).
当我问
?-friends(mia,X)。
时,它的本地堆栈就用完了

然后我加上

friends(ellen, mia) friends(lucy, mia) 
我问
?-朋友(mia,X)。
,它一直在回答
X=mia


我不明白,为什么它是递归的?

朋友/2的这一条款有缺陷:

friends(X,Y) :- friends(X,Z),friends(Y,Z).
把它翻译成英语:“如果
X
Y
有一个共同的朋友
Z
,那么
X
Y
就是朋友。”

或者,让我们专业化,让
X
成为“我”,让
Y
成为我的邻居“富伯特”,让
Z
成为“你”:所以如果我是你的朋友,富伯特是你的朋友。。。这能让我和富伯特成为朋友吗?我不这么认为,我讨厌那个家伙——他回家后总是砰的一声关上门


我建议你考虑关系<代码>朋友/ 2 < /代码>应该有的,可能有的,不应该有的。那么自反性、对称性、反对称性、及物性呢?

首先,两个假设:

  • 您想要编写的实际代码如下所示,带有适当的点:

    friends(mia,ellen).
    friends(mia,lucy).
    friends(X,Y) :- 
       friends(X,Z),
       friends(Z,Y).
    
  • 短暂性:朋友的朋友也是我的朋友(我更愿意将友谊建模为一种距离:“a接近B”,“B接近C”并不一定意味着“a接近C”)。首先弄清楚你想建模什么是正确的

现在,让我们来看看为什么我们进入无限递归

一步一步 那么,当我们问:
朋友(mia,X)
时会发生什么

  • 第一个子句给出了
    Y=ellen
    (您要求更多的解决方案)
  • 第二个子句给出了
    Y=lucy
    (您再次要求更多解决方案)
  • 堆栈溢出 让我们详细说明第三条:
  • 我想知道
    friends(mia,Y)
    是否适用于某个变量
    Y
  • 是否有一个变量
    Z
    使
    friends(mia,Z)
    有效

    请注意,除了将
    Y
    重命名为
    Z
    之外,我们还问了与上面步骤1相同的问题这闻起来像是无限递归,但让我们看看

  • 我们尝试了
    friends
    的前两个子句,但是失败了,因为没有
    friends(ellen,Y)
    friends(lucy,Y)
    ,所以
  • 我们调用第三个子句是为了发现是否存在可传递的友谊,我们回到了步骤1,没有进一步的=>无限递归
  • 这个问题类似于上下文无关语法中的无限

    修理 有两个谓词:

  • known\u friends/2
    ,提供直接关系
  • friends/2
    ,它也对及物性进行编码

    known_friends(mia,ellen).
    known_friends(mia,lucy).
    
    friends(X,Y) :- known_friends(X,Y).
    friends(X,Y) :- known_friends(X,Z), friends(Z,Y).
    
  • 现在,当我们问
    friends(mia,X)
    friends/2
    给出了与
    known\u friends/2
    的两个子句相同的答案,但没有找到传递子句的任何答案:这里的区别是
    known\u friends
    会有一点进步,即找到
    mia
    (无递归),并尝试(递归地)查找该朋友是否是其他人的朋友

    朋友的朋友 如果我们添加已知的朋友(ellen,bishop):-),那么
    朋友也会找到
    Y=bishop
    ,因为:

    • known\u friends(米娅,艾伦)
      hold,and
    • friends(ellen,bishop)
      是递归查找的
    圆度 如果您在友谊图中添加循环依赖项(在
    known\u friends
    中),那么您将使用
    friends
    无限遍历此图。在修复之前,你必须考虑以下问题:

    • friends(X,Y)friends(Y,X)
      是否适用于所有
      (X,Y)
    • 对于所有的
      X
      ,朋友(X,X)

    然后,在评估
    朋友
    时,您应该保留一组所有见过的人,以便在考虑上述属性的情况下,检测您在
    已知的朋友
    之间循环的时间。如果您想尝试,这应该不会太难实现。

    源文件中的
    friends/2
    子句不在一起意味着在
    friends/2
    子句的定义之间定义了其他子句。请注意,
    friends(mia,ellen)friends(mia,lucy)。
    不是有效的语法。所以我假设你所展示的并不是你的代码看起来的样子。。我只学了几个小时的序言。我想知道是否有人曾经用它来证明几何学中的某些东西,比如a线与b线平行,b线与c线平行,然后a线与c线平行。谢谢,现在我知道它为什么没有堆栈了。这是明确和有益的。