我一直在学习,我遇到了一个问题。我从教程中理解了cut操作符,但我正在尝试解决问题而我无法理解解决方案。
问题:
如果汽车颜色为红色,在意大利制造,那么它就是法拉利。如果它是红色但是在德国(或任何其他国家。可能不止一个)制造,那就是奔驰。如果它不是红色而且很大,那就是福特。如果它不是红色而不是大,那就是丰田。
那是:
red & Italy: Ferrari
red & Germany (or not Italy): Benz
not red & big: ford
not red & not big: Toyota
给出特定汽车对象的一些事实:
color(cx, red).
speed(cx, 220).
make(cx, italy).
type(cx, sport).
我想编写一个谓词brand(X, name)
,它将返回特定汽车对象的品牌,例如:
brand(X, ferrari):-
color(X,red), make(X,T), T=italy.
brand(X, benz) :-
color(X,red), not(make(X,italy)).
brand(X, ford) :-
not(color(X,red)), size(X,big).
brand(X, toyota) :-
not(color(X,red)), not(size(X,big)).
问题是我如何(以及在何处)使用切割算子,以便它不会检查相同的属性(例如:这里“make”)两次?我似乎无法绕过这个。
如果我检查红色然后再检查make,如果make不是意大利,那么如何为汽车对象“ck”的一组事实写brand(X, brand_name)
,这样它就不会检查再做一次?对我来说似乎不可能。
答案 0 :(得分:3)
答案简短:Don't。
几乎总是,使用!/0
会导致丢失有效的解决方案。
请始终牢记,Prolog程序通常比其他语言的程序更通用。请特别注意,用户始终可以发布最常见的查询,在您的情况下是:
?- brand(X, Y).
如果您在此定义中有!/0
,那么您可能“只检查一次”,但另一方面,无法生成所有有效答案。< / p>
一个好的方法是使用library(reif)
中的if_/3
。例如,在您的情况下,您可以将事实写为:
color(cx, red, true). speed(cx, 220, true). make(cx, italy, true). type(cx, sport, true).
现在你可以写:
car_type(C, Type) :- if_(color(C,red), if_(make(C, italy), Type=ferrari, Type=bentz), if_(type(C, big), Type=ford, Type=toyota)).
重要的是,即使有多个解决方案,最常见的查询仍然仍然有效:
?- car_type(C, Type). C = cx, Type = ferrari.