0

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

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

序言代码

    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....

我试着遍历整个事情,但我不确定它从布洛克到安妮,再到卡拉,一直到它循环到无限的真实。我有一种感觉,它与函数 (_) 中的通配符有关,但我不确定我还能如何表达函数的那部分,以便谓词在程序中搜索下一个事实,而不是跳到最后。

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

任何帮助是极大的赞赏。我不想要代码,我只想知道我做错了什么,这样我就可以学习如何正确地做。

谢谢。

4

1 回答 1

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 的用途,那么添加红色剪辑只会使您的问题更加复杂。
于 2013-04-22T03:45:49.770 回答