没有列表的Prolog关系跟踪

时间:2013-04-21 23:39:07

标签: prolog relationship backtracking predicates

我试图让一个谓词从一个事实到另一个事实联系起来,并一直持续到指定的停止点。

例如, 假设我正在做一个物流记录,我想知道谁从谁获得了一个包,他们从哪里获得它直到最后。

Prolog代码

    mailRoom(m).

    gotFrom(annie,brock).
    gotFrom(brock,cara).
    gotFrom(cara,daniel).
    gotFrom(daniel,m).


    gotFrom(X,Y) :- gotFrom(Y,_).

所以我试图用谓词gotFrom来做它是为了递归地从你开始的任何一点开始下去(例如:gotFrom(brock,Who))并到达由m指定的结尾,这是邮件室。

不幸的是,当我运行这个谓词时,它会读出来,

    Who = annie.
    Who = brock.
    Who = cara.
    etc.etc....

我试着踩过整个东西,但是我不确定它从布洛克到安妮的地方,到卡拉,一路向下,直到它循环通过真理无限。我觉得它与函数(_)中的通配符有关,但是我不知道我怎么能表达函数的那一部分才能让谓词在程序中搜索下一个事实而不是跳到最后。

我尝试在程序中使用backcut(!),但它给了我同样的错误。

非常感谢任何帮助。我不想要代码我只是想知道我做错了什么,所以我可以学习如何正确地做到这一点。

感谢。

1 个答案:

答案 0 :(得分:1)

我担心这条规则毫无意义:

gotFrom(X,Y) :- gotFrom(Y,_).

此处没有任何内容可以将X或Y约束到任何特定值。此外,单例变量X和匿名变量_的存在意味着基本上任何东西都可以工作。试试吧:

?- gotFrom([1,2,3], dogbert).
true ;
true ;

我认为你在这里建立的是某种传递属性。在这种情况下,你想要的可能更像是这样:

gotFrom(X,Z) :- gotFrom(X, Y), gotFrom(Y, Z).

这会产生一个有趣的结果:

?- gotFrom(brock, Who).
Who = cara ;
Who = daniel ;
Who = m ;
ERROR: Out of local stack

问题的原因可能不会立即显现出来。这是在该规则中发生两次未经检查的递归。我们递归地统一gotFrom/2,然后我们再次将它统一起来。最好将其分解为两个谓词,以便其中一个可以非递归地使用。

got_directly_from(annie,brock).
got_directly_from(brock,cara).
got_directly_from(cara,daniel).
got_directly_from(daniel,m).

gotFrom(X,Y) :- got_directly_from(X, Y).
gotFrom(X,Z) :- got_directly_from(X, Y), gotFrom(Y, Z).

这为我们提供了理想的行为:

?- gotFrom(brock, Who).
Who = cara ;
Who = daniel ;
Who = m ;
false.

请注意,这个对我无意义数据的攻击具有弹性:

?- gotFrom([1,2,3], dogbert).
false.

一些一般性建议:

  1. 永远不要忽略单例变量警告。他们几乎总是一个错误。
  2. 当您不明白发生了什么时,切勿引入切口。切割应仅在您首先了解行为并且了解切割将如何影响它的情况下使用。理想情况下,您应该尝试将自己限制在仅影响性能且没有可观察效果的绿色削减削减。如果您不明白Prolog的意图,那么添加红色只会让您的问题变得更加复杂。