2

我正在对 Prolog 进行破解(使用 SWI-Prolog),一切都按我的意愿进行,即逻辑计算正确,它找到了正确的解决方案,但整个回溯的事情让我很困惑。

这是代码:

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.

正如您从注释 1 和 2 中看到的那样,它等待我点击;继续,然后将第一个解决方案视为 null 并最终输出 false。

我可以使用削减来更好地控制这种行为,但我也希望以下命令能够正常工作:

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

和:

?- list_all_tall.
a
b
d
true.

这两个命令完全按照我想要的方式给出了解决方案。它只是注释 1 和注释 2 的那些让我陷入困境。tall(X).有没有一种方法可以让and的功能保持现在的list_all_tall.状态,同时根据我的喜好修复tall(a).and的功能tall(b).,即true.在我询问tall(a).或之后程序应该以 a 退出tall(b).

如果不是直接给出答案,而是有人可以实际解释我如何自己修复它,我将不胜感激,因为也许我在 Prolog 中的思维方式是完全不同的。

PS:没有针对高、瘦、胖、吃汉堡、玩电子游戏、素食者的冒犯。

4

3 回答 3

4

Just to supplement Daniel's well-explained answer (+1) for your specific case, consider:

tall(a).

Prolog will look at the first match, which is through:

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

This will succeed because skinny(a) will succeed. However, there's a disjunction ; leaving a choice point for Prolog that it hasn't explored yet. Because skinny(a) succeeds and the choice point is pending, you get true but prompted to seek more. Prolog then backtracks to the choice point and tries to satisfy eatless(a) but fails. Thus, you get:

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

Taking another example:

tall(d).

Again, this matches the tall/1 predicate, but this time, skinny(d) fails and prolog moves right on (due to the disjunction) to eatless(d) which succeeds. However, there are no more choice points after that success, so you get:

?- tall(d).
true.  % There were no choice points available after success
于 2014-01-06T18:29:52.603 回答
3

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

Prolog 不知道会有另一个答案。它只知道可能还有另一个答案。这称为选择点。每当 Prolog 遇到一个备选方案时,它都会创建一个选择点,然后遵循第一个选项。如果该选项不起作用,它会备份到最近的选择点并尝试下一个选项。如果在没有找到答案的情况下用尽了备选方案,您将得到nofalse

您可以尝试编写代码,这样如果您知道没有更多项目,您就不会获得选择点。member/2,例如,在某些 Prologs 中,您会false在最后一项之后获得,而在其他 Prologs 中则不会。但是,在您的所有解决方案之后有一个无用的选择点并不是一个构图问题。您的用户界面可能不会直接向用户显示 Prolog 的提示。您可以使用setof/3和其他逻辑外谓词来获得所有解决方案。false不会“泄漏”到世界上。一开始有点不安,但只要相信它,不要太担心它。

于 2014-01-06T18:17:19.467 回答
2

tall/1在这种情况下,可以基于不同的实例化模式以不同的模式运行相同的谓词。当您运行时,您实例化参数(即)并且您想要接收或(并且没有选择点,由 表示)。在 Prolog 中,这种模式称为semi-deterministic?- tall(a).X=atruefalse;

您可以通过以下方式强制您的谓词对于这个特定的实例化模式是半确定的:

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.

希望这可以帮助!

于 2014-04-05T13:28:44.033 回答