序言存在时不给我解决方案
prolog doesn't give me a solution when one exists
我正在 七周学习七种语言,但我对 prolog 有一些不了解的地方。我有以下程序(基于他们的 wallace 和 grommit 程序):
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- \+(X = Y), onTeam(X, Z), onTeam(Y, Z).
并像这样加载它
?- ['teams.pl'].
true.
但它没有给我任何解决以下问题的方法
?- teamMate(a, X).
false.
它可以解决更简单的问题(如书中所示):
?- onTeam(b, X).
X = aTeam ;
X = superTeam.
还有解决办法:
?- teamMate(a, b).
true ;
false.
我错过了什么?我已经尝试过 gnu prolog 和 swipl。
...还有更多...
当您将 "can't be your own teammate" 限制移动到结束时:
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- onTeam(X, Z), onTeam(Y, Z), \+(X = Y).
它给了我期望的解决方案:
?- ['teams.pl'].
true.
?- teamMate(a, X).
X = b.
?- teamMate(b, X).
X = a ;
X = c.
什么给了?
你观察得很好!事实上,情况更糟,因为即使 最一般的 查询 也会失败 :
?- teamMate(X, Y).
false.
声明地,这意味着 "there are no solutions whatsoever",这显然是 错误的 而不是我们期望关系的行为方式:如果有解决方案,那么 更多一般 查询不得失败。
您出现这种奇怪且逻辑上不正确的行为的原因是 (\+)/1
只有在其参数 充分实例化 时才是正确的。
要以更通用的方式表达术语的不质量,它可以正常工作无论参数是否被实例化,使用dif/2
,或者,如果您的 Prolog 系统不提供它,您可以在 prolog-dif 标签。
例如,在您的情况下(note_that_I_am_using_underscores_for_readability
而不是 tuckingTheNamesTogetherWhichMakesThemHarderToRead
):
team_mate(X, Y) :- dif(X, Y), on_team(X, Z), on_team(Y, Z).
您的查询现在完全符合预期:
?- team_mate(a, X).
X = b.
最一般的查询当然也能正常工作:
?- team_mate(X, Y).
X = a,
Y = b ;
X = b,
Y = a ;
X = b,
Y = c ;
etc.
因此,使用dif/2
来表达不平等保留logical-purity你们的关系:系统现在不再简单地说false
即使有解决方案。相反,您会得到您期望的答案!请注意,与之前相比,这同样有效无论您在哪里拨打电话!
为您提供了一些高级注意事项和解决方案。我的回答更多是关于根本原因,您可能感兴趣也可能不感兴趣。
(顺便说一下,在学习 Prolog 时,我问了同一个用户很多 the same question and got a very similar answer。太好了。)
证明树
您有一个问题:
Are two players team mates?
要从 Prolog 获得答案,您需要制定一个查询:
?- team_mate(X, Y).
其中 X 和 Y 都可以是自由变量或绑定变量。
根据您的谓词数据库(事实和规则),Prolog 会尝试找到证明 并为您提供解决方案。序言 searches for a proof by doing a depth-first traversal of a proof tree.
在您的第一个实现中,\+ (X = Y)
出现在其他任何东西之前,因此它位于树的根节点,并且将在以下目标之前进行评估。如果 X
或 Y
是自由变量,则 X = Y
必须成功 ,这意味着 \+ (X = Y)
必须失败。所以查询一定会失败.
另一方面,如果 X
或 Y
是自由变量,dif(X, Y)
将成功 ,但稍后的尝试将它们彼此统一 必须失败 。到那时,Prolog 将不得不在证明树的另一个分支下寻找证明,如果还有的话。
(考虑到证明树,尝试找出一种实现 dif/2
的方法:你认为没有任何一个 a)添加某种状态到 [=19= 的参数中是可能的吗? ] 或 b) 更改解析策略?)
最后,如果你把 \+ (X = Y)
放在最后,并注意 X
和 Y
在计算时都被磨碎了,那么统一就变成了更像是一个简单的比较,它可以失败,所以否定可以成功。
我正在 七周学习七种语言,但我对 prolog 有一些不了解的地方。我有以下程序(基于他们的 wallace 和 grommit 程序):
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- \+(X = Y), onTeam(X, Z), onTeam(Y, Z).
并像这样加载它
?- ['teams.pl'].
true.
但它没有给我任何解决以下问题的方法
?- teamMate(a, X).
false.
它可以解决更简单的问题(如书中所示):
?- onTeam(b, X).
X = aTeam ;
X = superTeam.
还有解决办法:
?- teamMate(a, b).
true ;
false.
我错过了什么?我已经尝试过 gnu prolog 和 swipl。
...还有更多...
当您将 "can't be your own teammate" 限制移动到结束时:
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- onTeam(X, Z), onTeam(Y, Z), \+(X = Y).
它给了我期望的解决方案:
?- ['teams.pl'].
true.
?- teamMate(a, X).
X = b.
?- teamMate(b, X).
X = a ;
X = c.
什么给了?
你观察得很好!事实上,情况更糟,因为即使 最一般的 查询 也会失败 :
?- teamMate(X, Y). false.
声明地,这意味着 "there are no solutions whatsoever",这显然是 错误的 而不是我们期望关系的行为方式:如果有解决方案,那么 更多一般 查询不得失败。
您出现这种奇怪且逻辑上不正确的行为的原因是 (\+)/1
只有在其参数 充分实例化 时才是正确的。
要以更通用的方式表达术语的不质量,它可以正常工作无论参数是否被实例化,使用dif/2
,或者,如果您的 Prolog 系统不提供它,您可以在 prolog-dif 标签。
例如,在您的情况下(note_that_I_am_using_underscores_for_readability
而不是 tuckingTheNamesTogetherWhichMakesThemHarderToRead
):
team_mate(X, Y) :- dif(X, Y), on_team(X, Z), on_team(Y, Z).
您的查询现在完全符合预期:
?- team_mate(a, X). X = b.
最一般的查询当然也能正常工作:
?- team_mate(X, Y). X = a, Y = b ; X = b, Y = a ; X = b, Y = c ; etc.
因此,使用dif/2
来表达不平等保留logical-purity你们的关系:系统现在不再简单地说false
即使有解决方案。相反,您会得到您期望的答案!请注意,与之前相比,这同样有效无论您在哪里拨打电话!
(顺便说一下,在学习 Prolog 时,我问了同一个用户很多 the same question and got a very similar answer。太好了。)
证明树
您有一个问题:
Are two players team mates?
要从 Prolog 获得答案,您需要制定一个查询:
?- team_mate(X, Y).
其中 X 和 Y 都可以是自由变量或绑定变量。
根据您的谓词数据库(事实和规则),Prolog 会尝试找到证明 并为您提供解决方案。序言 searches for a proof by doing a depth-first traversal of a proof tree.
在您的第一个实现中,\+ (X = Y)
出现在其他任何东西之前,因此它位于树的根节点,并且将在以下目标之前进行评估。如果 X
或 Y
是自由变量,则 X = Y
必须成功 ,这意味着 \+ (X = Y)
必须失败。所以查询一定会失败.
另一方面,如果 X
或 Y
是自由变量,dif(X, Y)
将成功 ,但稍后的尝试将它们彼此统一 必须失败 。到那时,Prolog 将不得不在证明树的另一个分支下寻找证明,如果还有的话。
(考虑到证明树,尝试找出一种实现 dif/2
的方法:你认为没有任何一个 a)添加某种状态到 [=19= 的参数中是可能的吗? ] 或 b) 更改解析策略?)
最后,如果你把 \+ (X = Y)
放在最后,并注意 X
和 Y
在计算时都被磨碎了,那么统一就变成了更像是一个简单的比较,它可以失败,所以否定可以成功。