我尝试实施
时遇到了一些问题friends(mia, ellen).
friends(mia, lucy).
friends(X,Y) :-
friends(X,Z),
friends(Y,Z).
当我问?- friends(mia, X).
时,它会耗尽本地堆栈。
然后我添加
friends(ellen, mia) friends(lucy, mia)
我问?- friends(mia, X).
,它不断回复X = mia
。
我无法理解,为什么它是递归的?
答案 0 :(得分:2)
friends/2
的这一条款存在缺陷:
friends(X,Y) :- friends(X,Z),friends(Y,Z).
将其翻译成英语:"如果X
和Y
有共同的朋友Z
,那么X
和Y
就是朋友。& #34;
或者,让我们专注,让X
成为" me",让Y
成为我的邻居" FooBert",然后让{{ 1}} be"你":所以,如果我是你的朋友而FooBert是你的朋友......这会让我和FooBert成为朋友吗?我不这么认为,我讨厌那个人 - 他回家后总是砸门。 :)
我建议您考虑Z
应该所拥有的代数属性,可能所拥有的代数属性,以及不应该< / em>有。那么反身性,对称性,反对称性,传递性呢?
答案 1 :(得分:2)
首先,两个假设:
您要编写的实际代码如下,并带有适当的点:
friends(mia,ellen).
friends(mia,lucy).
friends(X,Y) :-
friends(X,Z),
friends(Z,Y).
变性持有:朋友的朋友也是我的朋友(我宁愿把友谊模仿为距离:“A在B附近”,“B在C附近”并不一定意味着“A在C附近”) 。 repeat's answer首先要弄清楚你想要建模的内容。
现在,让我们看看为什么我们进入无限递归。
那么,当我们问:friends(mia,X)
?
Y=ellen
(您需要更多解决方案)Y=lucy
(您再次要求提供更多解决方案)friends(mia,Y)
是否适用于某个变量Y
。是否存在Z
变量friends(mia,Z)
?
请注意,除了从Y
重命名为Z
之外,我们问的问题与上面的第1步相同吗? 这闻起来像无限递归强>,但让我们看看......
friends
的前两个条款,但之后我们失败了,因为没有friends(ellen,Y)
也没有friends(lucy,Y)
,所以...... 此问题类似于无上下文语法中的无限Left recursion。
有两个谓词:
known_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_friends/2
的两个条款相同的答案,但没有找到传递条款的任何答案:这里的区别是known_friends
会取得一些进展,即找到mia
的已知朋友(没有递归),并试图找到(递归)该朋友是否是其他人的朋友。
如果我们添加known_friends(ellen, bishop)
: - ),那么friends
也会找到Y=bishop
,因为:
known_friends(mia,ellen)
成立,friends(ellen,bishop)
是递归发现的。如果您在友谊图表中添加循环依赖关系(在known_friends
中),那么将使用friends
对此图表进行无限遍历。在解决这个问题之前,您必须考虑以下问题:
friends(X,Y) <=> friends(Y,X)
对所有人(X,Y)
都有效吗?friends(X,X)
对所有X
然后,在评估friends
时,您应该保留一组所有看到的人,以便检测您何时循环known_friends
,同时考虑上述属性。如果你想尝试,这也不应该太难实现。