序言关系和比较

prolog relation and comparison

假设我有这些关系

drive(adam, van).
drive(betty, tank).
drive(adam, truck).
drive(adam, convertible).

如何编写条件来找出亚当驾驶三辆不同的车辆?

我试过了,但是没用。

drivethree(A):-    
  drive(A, X),
  drive(A, Y), 
  drive(A, Z),
  X = not(Y),
  X = not(Z),
  Y = not(Z).

如果您打算 'drives at least 3',您的代码在更正后应该可以工作:

...
X = not(Y),
X = not(Z),
...

应该是

...
X \= Y,
X \= Z,
...

否则,对于 'drives exactly 3' 的更实用的定义,您可以使用 setof/3:

drivethree(A) :- setof(V, drive(A,V), [_,_,_]).

起初,您可能想了解为什么您的程序无法运行。毕竟,这可能不是唯一导致问题的程序。

识别不正确的测试用例

问题是 drivethree(X) 在您期望它工作时没有成功。我们如何定位问题?

概括你的程序

一种可能性是通过一个接一个地删除目标来概括您的程序。如果生成的程序仍然失败,则即使是极小的剩余部分也一定有错误!无需一次阅读所有内容。

我会在要删除的目标前面加一个*

:- op(950,fy, *).
*_.

drivethree(A):-    
   drive(A, X),
   * drive(A, Y), 
   * drive(A, Z),
   X = not(Y),
   * X = not(Z),
   * Y = not(Z).

在这个新程序中 drivethree(A) 仍然失败,但只使用了两个目标。所以这两个目标肯定有some bug。为了更好地了解这一点,请尝试查询:

?- drive(A, X), X = not(Z).
false.

又一次失败了。现在,我们将只尝试第一个目标:

?- drive(A, X).
A = adam,
X = van ;
A = betty,
X = tank ...

所以 X 一定是某个原子,但是 X = not(Z) 要求它是一个具有函子 not/1.

的结构

要表达不平等,最好使用dif(X, Z) see this for more。实际上使用:

drivethree(A):-
   dif(X, Y),
   dif(X, Z),
   dif(Y, Z),    
   drive(A, X),
   drive(A, Y), 
   drive(A, Z).

但是回到你的实际问题。您在这里描述的是 至少 三辆车的人。

单调性

现在想象一下,我们正在向您的程序中添加新事实 drive/2。会发生什么? adam 仍然是一个解决方案吗?事实上,如果我们只添加更多的事实,他将永远是一个解决方案。这种 属性 被称为单调性。通过添加更多子句,您只会增加解决方案集。

考虑一下您想要描述正好 三辆车的人。稍等片刻,想想如果我们在这样的程序中添加新的事实会发生什么。现在可能 adam 不再是解决方案,因为他现在可能驾驶四辆或更多辆汽车。这样的程序称为非单调。开始学习Prolog时,第一次远离非单调程序,坚持使用单调程序。