序言关系和比较
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时,第一次远离非单调程序,坚持使用单调程序。
假设我有这些关系
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时,第一次远离非单调程序,坚持使用单调程序。