我正在尝试用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应该失败。
答案 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时,A
为0
。但是,在顶层,你没有看到这个,因为这个变量只发生在
有几种方法可以解决。其中之一是使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
。