Prolog - 约束库 - 变量范围

Prolog - Constraint Library - Variable Scope

我正在尝试用 Prolog 解决 LSAT 逻辑问题。我试图让 Prolog 告诉我一行中演员的可能值是否有效。

我写了以下内容:

:- use_module(library(clpfd)).

actor("Jeff",A) :-
        A #>= 0,
        A #<5.
actor("Rich",C) :-
        C #>= 0,
        C #<5,
        actor("Jeff",A),
        A #< C.

当我查询时:

?- actor("Rich",0).
false.

这是对的,因为 Jeff < 比 Rich 和 Jeff => 0 所以 Rich 不能是 0。

但是,当我查询时:

?- actor("Jeff",1), actor("Rich",1).
true 

我也明白了,这是不可能的,因为 Rich > Jeff。

我觉得问题出在我的变量上。我不明白

actor("Jeff",A),
A #< C.

正在评估。在我看来,应该将 actor("Jeff",A) 设置为 actor("Jeff",1) 然后 1 #< 1 应该失败。

变量一个子句或局部到该子句。

对于您的情况,要了解问题,请首先考虑以下查询:

?- actor("Rich", C),
   C = 1.
C = 1.

这并没有告诉我们很多,所以我们应用以下纯粹的代数推理:对于目标 actor("Rich", C),我们替换单个匹配子句的 body :

?- C #>= 0,
   C #< 5,
   actor("Jeff",A),
   A #< C,
   C = 1.

答案是:

C = 1,
A = 0.

这表明当C为1时,则A0。但是,在顶层,您没有看到这一点,因为该变量仅出现在 within "Rich" 的子句中。明确表示有一个 解决方案 满足该子句中的约束,但它没有 link 我们想要的变量。

有几种出路。其中之一是使 A 作为 参数 可用,以便您可以从顶层明确引用它。一般来说,为了link相关实体在一起,你必须为你的子句每个引入参数,这样你就可以引用你需要推理的变量,而不是在每个子句中引入新的。

例如,在您的情况下,这可能如下所示:

actor("Jeff", A, _) :-
        A #>= 0,
        A #< 5.

actor("Rich", A, C) :-
        C #>= 0,
        C #< 5,
        actor("Jeff", A, C),
        A #< C.

我用 A 指代 Jeff,用 C 指代 Rich。

趁我们在的时候,让我们整理代码,并使用以下本质上等效版本:

actor(jeff, A, _) :- A in 0..4.
actor(rich, A, C) :- C in 0..4, actor(jeff, A, C), A #< C.

确保您理解以下答案:

?- actor(jeff, 1, C), actor(rich, C, 1).
C = 0.

您的原始示例现在产生 false,完全符合预期:

?- actor(rich, 1, 1).
false.

因此,原则上应该可以解决你的任务。

但是,有一种更简单的方法可以解决所有这些问题,它可以避免具体化过载

与其煞费苦心地跟踪名称和相应变量之间的联系,不如让我们直接使用带有预期名称的变量。比如这个你怎么说:

?- Jeff in 0..4,
   Rich in 0..4,
   Jeff #< Rich.

这使用Prolog 变量来表示人,并使工作变得更加简单。在此表示中,您的查询变为:

?- Jeff in 0..4,
   Rich in 0..4,
   Jeff #< Rich,
   Jeff = 1,
   Rich = 1.

这显然会导致 false