对于给定的事实:
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: check transitivity for simple facts中描述的堆栈溢出问题。
解决方案本身就像一个魅力。但是,我对双倍trust_direct(A, B)
感到困惑。为什么这有必要?
trusts(A, C)
谓词是否已涵盖trust_direct(A, B)
关系?
答案 0 :(得分:4)
这是一个很好的问题!
为了说明原因,我使用以下定义来启用声明性调试:
:- op(920,fy, *). *_.
我现在可以将*
置于任何目标之前将其概括为。声明地说,这意味着我可以简单地忽略目标(回想一下目标始终是约束,限制任何解决方案)。我当然也可以简单地评论目标,但这对于子句体的 last 目标来说效果不佳。
现在考虑你的定义:
trusts(A, B) :- trust_direct(A, B). trusts(A, C) :- trust_direct(A, B), trusts(B, C).
现在,为了回答你非常合理的问题,假设我们只有有第二个条款,即:
trusts(A, C) :- trust_direct(A, B), trusts(B, C).
为了让我们的生活更简单,我现在概括这个定义如下:
trusts(A, C) :- *trust_direct(A, B), trusts(B, C).
> 片段,然后trusts(X, Y)
也保留此定义。
我使用删除文本来表示不相关的目标(因为它们被推广)。所以,这在声明上等同于:
trusts(A, C) :- trusts(B, C).
让我们以声明的方式阅读 :
X
持有如果Y
成立。
但是当 trusts(X, Y)
举行时?当然(通过简单地再次应用定义),如果 trusts(A, C)
成立。并且当这样做时?当然(通过简单地应用定义), if ...等。从这里,很容易看出我们永远不会找到任何trusts(B, C)
和trusts(B, C)
以便trusts(B', C')
完全拥有。
而尽管事实上这实际上是原始子句的明显更通用的版本!因此,没有丝毫希望满足更具体的版本!
这回答了我们的问题:我们需要一个实际上持有的案例,以及比谈论A
更简单的事情,这实际上是我们绝对的最简单的情况期待更通用的关系C
来保持 。
因此从这种情况开始是很自然的,并说:
如果
trusts(A, C)
持有,则trust_direct/2
成立。
在Prolog:
trusts(X, Y) :- trust_direct(X, Y).
这正是你的第一个条款!