2

对于给定的事实:

trust_direct(p1, p2).
trust_direct(p1, p3).
trust_direct(p2, p4).
trust_direct(p2, p5).
trust_direct(p5, p6).
trust_direct(p6, p7).
trust_direct(p7, p8).
trust_direct(p100, p200).

这个解决方案:

trusts(A, B) :-
        trust_direct(A, B).
trusts(A, C) :-
        trust_direct(A, B),
        trusts(B, C).

...用于改善Prolog 中描述的堆栈溢出问题:检查传递性以获取简单的事实

解决方案本身就像一个魅力。但是,我对双倍的trust_direct(A, B). 为什么这是必要的?

谓词不应该trusts(A, C)已经涵盖了trust_direct(A, B)关系吗?

4

1 回答 1

4

这是一个很好的问题!

为了说明原因,我使用以下定义来启用声明式调试

:- op(950,fy, *)。

*_。

我现在可以把*前面的任何目标一概而论了。声明式地,这意味着我可以简单地忽略目标(回想一下,目标始终是一个约束,限制任何解决方案)。我当然也可以简单地评论目标,但这对于条款主体的最后一个目标并不适用。

现在考虑您的定义:

信任(A,B):-
        信任直接(A,B)。
信任(A,C):-
        信任直接(A,B),
        信任(B,C)。

现在,要回答您非常合理的问题,假设我们只有第二个子句,即:

信任(A,C):-
        信任直接(A,B),
        信任(B,C)。

为了让我们的生活更简单,我现在将这个定义概括如下:

信任(A,C):-
         *  trust_direct(A,B),
        信任(B,C)。

这比前面的代码片段更通用:如果 trusts(X, Y)对任何XY前面的代码片段都成立,那么对于这个定义trusts(X, Y) 也成立。

我使用了删除文本来表示不相关的目标(因为它们被概括了)。因此,这在声明上等同于:

信任(A,C):-
        信任(B,C)。

让我们以声明的方式阅读:

trusts(A, C)持有,如果 trusts(B, C)持有。

但什么时候举行trusts(B, C)?当然(通过简单地再次应用定义),如果 trusts(B', C')成立。这什么时候成立?当然(通过简单地应用定义),如果 ... 等等。从这里,很容易看出我们永远不会找到任何AC所以它完全trusts(A, C)成立。

尽管事实上这实际上是原始条款的更通用的版本!因此,更没有希望满足更具体的版本!

这回答了我们的问题:我们需要一个实际成立的情况,还有什么比谈论更简单的事情trust_direct/2,这确实是最简单的情况,我们当然希望更一般的关系trusts/2成立。

因此很自然地从这个案例开始,然后说:

如果 trust_direct(X, Y)持有 trusts(X, Y)持有。

在 Prolog 中:

信任(X,Y):-信任直接(X,Y)。

这正是你的第一个子句!

于 2017-02-27T22:00:18.533 回答