Prolog - 约束库 - 可变范围

时间:2017-04-10 22:04:42

标签: prolog clpfd

我正在尝试用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.

这是正确的,因为杰夫是&lt;比Rich和Jeff是=&gt; 0所以Rich不能为0。

但是,当我查询时:

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

我也是如此,这是不可能的,因为Rich&gt;杰夫。

我觉得问题是因为我的变量发生了什么事。我不明白怎么做

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

正在评估。在我看来,演员(&#34;杰夫&#34;,A)应该设置为演员(&#34;杰夫&#34;,1)然后1#&lt; 1应该失败。

1 个答案:

答案 0 :(得分:1)

子句中的变量或该子句的 local

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

?- 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。但是,在顶层,你没有看到这个,因为这个变量只发生在 的子句中。明确显示有一个解决方案满足该子句中的约束,但它没有链接到我们想要的变量。

有几种方法可以解决。其中之一是使A可用作参数,以便您可以从顶层显式引用它。通常,要将相关实体链接在一起,您必须为子句中的每个引入参数,以便您可以引用需要推理的变量,而不是在每个中引入新的变量。子句。

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

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