Prolog回溯寻找解决方案并返回虚假

时间:2014-01-06 18:06:14

标签: prolog backtracking prolog-toplevel

我在Prolog(使用SWI-Prolog)进行了一次破解,一切都像我想要的那样,即逻辑计算正确,它找到了正确的解决方案,但整个回溯的事情正在困扰着我。 / p>

以下是代码:

tall(X) :- skinny(X) ; eatless(X).
eatless(X) :- playsmore(X).
playsmore(X) :- hasxbox(X) ; hasplaystation(X).

skinny(a).
vegetarian(a).
hasxbox(b).
eatsburger(c).
hasplaystation(d).

list_all_tall :- forall(tall(Tall), writeln(Tall)).

非常基本的东西。以下是我查询后得到的结果:

?- tall(a).
true ; % Note 1
false.

?- tall(b).
true ; % Note 2
false.

?- tall(c).
false.

?- tall(d).
true.

从Notes 1和2中可以看出,它等待我点击;继续前进,然后将第一个解决方案视为null并最终输出false。

我可以使用剪切来更好地控制此行为,但我还希望以下命令正常工作:

?- tall(X).
X = a ;
X = b ;
X = d.

?- list_all_tall.
a
b
d
true.

这两个命令完全按我想要的方式提供解决方案。它只是Notes 1和2中的那些让我崛起的。有没有一种方法可以保留tall(X).list_all_tall.的功能,同时根据我的喜好修复tall(a).tall(b).的功能,即在我询问true.tall(a).

后,该程序应以tall(b).退出

我很感激,如果不是直接回答,有人可以解释我怎么能自己解决这个问题,因为也许我在Prolog中的思维方式都是吵闹的。

PS:没有冒犯高,瘦,脂肪,吃汉堡,玩电子游戏,吃素的人。

3 个答案:

答案 0 :(得分:3)

为了补充Daniel针对您具体案例的解释清楚的答案(+1),请考虑:

tall(a).

Prolog会看第一场比赛,通过:

tall(X) :- skinny(X) ; eatless(X).

这将成功,因为skinny(a)将成功。然而,有一个脱节;为Prolog留下了尚未探索的选择点。由于skinny(a)成功并且选择点处于待处理状态,因此您会获得true,但会提示您寻求更多。然后Prolog回溯到选择点并尝试满足eatless(a)但是失败了。因此,你得到:

?- tall(a).
true ; % because `skinny(a)` succeeded
false. % because `eatless(a)` failed

再举一个例子:

tall(d).

同样,这与tall/1谓词匹配,但这一次,skinny(d)失败并且prolog正好(由于分离)向eatless(d)成功移动。但是,在成功之后没有更多的选择点,所以你得到:

?- tall(d).
true.  % There were no choice points available after success

答案 1 :(得分:2)

最好的办法是不要担心,因为你并不总是能够阻止它。

Prolog从来不知道成为另一个答案。它只知道可能是另一个答案。这被称为选择点。每当Prolog达到替代方案时,它会创建一个选择点,然后遵循第一个选项。如果该选项不起作用,它将备份到最近的选择点并尝试下一个选项。如果在没有找到答案的情况下用完替代品,则会获得nofalse

您可以尝试编写代码,这样如果您知道没有其他项目,则无法获得选择点。 member/2,例如,在某些Prolog中,您在最后一个项目后获得false,而在其他项目中则不是。setof/3。但是,在你所有的解决方案之后,选择点是不是一个组合问题。您的用户界面可能不会直接向用户显示Prolog的提示。您可以使用false和其他extralogical谓词来获取所有解决方案。 {{1}}不会“泄漏”到世界各地。一开始有点令人不安,但只要相信它,不要太担心它。

答案 2 :(得分:1)

在这种情况下,可以根据不同的实例化模式以不同的模式运行相同的谓词tall/1。 当您运行?- tall(a).时,您实例化参数(即X=a),并且您希望收到truefalse(并且没有选择点,由;指示)。 在Prolog中,此模式称为半确定性

您可以通过以下方式强制您的谓词对此特定实例化模式具有半确定性:

tall(X):- (ground(X) -> once(tall0(X)) ; tall0(X)).

这里ground(X)成功,以防X完全实例化。 完全实例化意味着它不是变量,也不是包含变量的复合词。 tall0(X)是您的原始谓词。

您要使用的第二种模式是?- tall(X). 在这里,您希望随后使用;给出所有结果。 此模式在Prolog中称为非确定性

您的示例的完整代码是:

tall(X):- (ground(X) -> once(tall0(X)) ; tall0(X)).
tall0(X):- skinny(X) ; eatless(X).
eatless(X):- playsmore(X).
playsmore(X):- hasxbox(X) ; hasplaystation(X).
skinny(a).
hasxbox(b).
hasplaystation(d).

现在可以在两种模式中调用单个谓词tall/1,从而产生所需的行为。半确定性用法:

?- tall(a).
true.

非确定性用法:

?- tall(X).
X = a ;
X = b ;
X = d.

希望这有帮助!