Sup*_*ell 4 prolog zebra-puzzle
我似乎无法让我的if else声明工作.
male(john).
male(fred).
male(harry).
female(mary).
female(julie).
female(susan).
female(anne).
hasblonde(X):-(male(X),X = john);(female(X),X = susan);(female(X),X = julie).
hasdarkhair(X):-(male(X),X = harry);(male(X),X = fred).
hasbrunette(X):-(female(X),X = mary);(female(X),X = anne).
isrich(X):-(female(julie),X=julie);(male(fred),X=fred).
likes(male(X),female(Y));likes(female(X),male(Y)):-likes(X,Y).
likes(X,Y):-
((X==julie)->
((hasdarkhair(Y))->
(female(X), male(Y));
male(X));
female(X),male(Y));
((X==julie)->
((isrich(Y))->
(female(X), male(Y));
male(X));
female(X),male(Y));
((X=mary)->
((hasdarkhair(Y))->
(female(X), male(Y));
male(X));
female(X),male(Y));
((X=john)->
((isrich(Y))->
(female(X), male(Y));
female(X));
male(X),female(Y));
((X=harry)->
((isrich(Y))->
(female(X), male(Y));
female(X));
male(X),female(Y));
((X=fred)->
((hasbrunette(Y))->
(female(X), male(Y));
female(X));
male(X),female(Y)).
Run Code Online (Sandbox Code Playgroud)
我想(Statement) - >(如果是,则运行此语句);(如果为false则运行此语句).是Prolog的正确方法.无论我写什么,为什么会这样
likes(MaleName,FemaleName)
likes(FemaleName,MaleName)
Run Code Online (Sandbox Code Playgroud)
它返回true?
小智 5
以CapelliC的答案为基础,因为显然他的回答并不明确.至于if-else语法和用法,请参阅答案的结尾.
首先,您在问题陈述中的内容是您希望以Prolog程序的形式表示的信息.在Prolog中,你有谓词,它可以描述他们的论点之间的关系,或陈述关于他们的论点的已知真相.这里例如是一个事实表; 它说我们知道有七个人存在:
person(john). person(fred). person(harry). person(mary). person(julie). person(susan). person(anne).
好的.我们现在要说的是,其中一些是男性,一些是女性.
% John, Fred and Harry are men, Mary, Julie, Susan and Anne are women. male(john). male(fred). male(harry). female(mary). female(julie). female(susan). female(anne).
这是另外两个事实表.现在,您要向数据库添加有关其头发颜色的信息:
% John has blonde hair while Fred and Harry have dark hair. % Julie and Susan are blonde, Mary and Anne are brunette. person_hair(john, blond). person_hair(fred, dark). person_hair(harry, dark). person_hair(julie, blond). person_hair(susan, blond). person_hair(mary, dark). person_hair(anne, dark).
如果你愿意,这是一个有两列的表:第一个是人,第二个是头发颜色的描述."黑妞"这个词通常用来形容一个黑头发的女人,所以我们可以添加一条规则来说明:
% A brunette is a female with dark hair brunette(X) :- female(X), person_hair(X, dark).
在我们的计划中,我们拥有黄金并拥有黄金的一些人会让人变得富有:
person_owns(fred, gold). person_owns(julie, gold). is_rich(X) :- %person(X), person_owns(X, gold).
在我们严格的异性恋计划中,男性喜欢女性,女性喜欢男性:
person_likes(M, F) :- male(M), female(F). person_likes(F, M) :- female(F), male(M).
正如您可以计算的那样,这为我们提供了3 x 4 + 4 x 3 = 24种可能的解决方案,person_likes(A, B)
无需任何进一步限制:
?- bagof(A-B, person_likes(A, B), R), length(R, Len). R = [john-mary, john-julie, john-susan, john-anne, fred-mary, fred-julie, fred-susan, fred-anne, ... - ...|...], Len = 24.
这是一个非常通用的规则:它描述了自由变量之间的关系,这使得它与我们的person_owns/2
关系有所不同,例如.它真的有用吗?为什么不:
is_heterosexual(H) :- person(H).
但这仅表明我们计划中的每个人都是异性恋者; 它不会让我们得出异性恋者喜欢异性的规则.也许更好地重新命名它,以更好地表达它的含义(我将使用if-then-else结构,以显示它是如何正常完成的):
opposite_sex(X, Y) :- ( male(X) -> female(Y) ; female(X) -> male(Y) ).
就我们的目的而言,这可能与上面的内容一样:
opposite_sex(M, F) :- male(M), female(F). opposite_sex(F, M) :- male(M), female(F).
有了这个,我们可以编写一个规则,person_likes/2
其中包含一个前提条件,说明另一个必须属于异性:
person_likes(X, Y) :- opposite_sex(X, Y), fits_personal_taste(X, Y).
我们现在可以为每个人的个人品味制定规则.对于朱莉:
fits_personal_taste(julie, X) :- is_rich(X), person_hair(X, dark).
然而,这会产生一个小问题.您需要确保程序知道的每个人都有这种形式的规则.我们不知道Anne的任何偏好,所以我们必须有一个规则:
% Anyone (male) would fit Anne's tastes fits_personal_taste(anne, _).
这将是更好,如果我们能够代替有一个表格,表格中每个人的条目确实有偏好,例如:
person_preferences(julie, [is_rich, person_hair(dark)]). person_preferences(harry, [is_rich]). % and so on
这将允许我们写fits_personal_taste/2
这样的东西:
fits_personal_taste(X, Y) :- ( person_preferences(X, Ps) -> maplist(fits_preference(Y), Ps) ; true ).
这是Prolog中if-else结构的预期用法:异或.
如果一个人有偏好,检查候选人是否适合所有人; 否则成功.
如何将fits_preference/2
看起来像有关系吗?它需要一个人作为第一个参数,一个在第二个参数中具有偏好的术语,并且必须以某种方式检查该人是否满足该偏好.一个有点hacky的解决方案是使用所谓的Univ运算符=..
来获取表单person_hair(Color)
的术语,创建表单的术语person_hair(Person, Color)
,并将其命名为:
fits_preference(Person, Preference) :-
Preference =.. [F|Args],
Preference1 =.. [F,Person|Args],
call(Preference1).
Run Code Online (Sandbox Code Playgroud)
person_preferences
将一个人直接映射到可调用术语可能更好:
person_preferences(julie, P, [is_rich(P), person_hair(P, dark)]). person_preferences(harry, P, [is_rich(P)]). % and so on
有了这个,fits_personal_taste/2
变成:
fits_personal_taste(X, Y) :- ( person_preferences(X, Y, Ps) -> maplist(call, Ps) ; true ).
当person_preferences/3
在语句的条件部分中调用时,首选项列表中的每个首选项都绑定到具体的人; 然后我们打电话给每个人检查是否可以证明我们的计划中的事实是真实的.
最后,一个帮助器谓词possible_pair/2
,表明两个人都需要彼此喜欢:
possible_pair(X, Y) :-
person_likes(X, Y),
person_likes(Y, X),
X @< Y.
Run Code Online (Sandbox Code Playgroud)
最后一行将确保我们不会通过假设两个人应该严格按顺序两次获得相同的对.
有了这个,我得到:
?- bagof(A-B, possible_pair(A, B), R).
R = [fred-mary, anne-fred].
Run Code Online (Sandbox Code Playgroud)
或者,对于单向"喜欢"的列表,
?- bagof(A-B, person_likes(A, B), R), write(R).
[john-julie,fred-mary,fred-anne,harry-julie,susan-john,anne-john,mary-fred,julie-fred,susan-fred,anne-fred,mary-harry,susan-harry,anne-harry]
R = [john-julie, fred-mary, fred-anne, harry-julie, susan-john, anne-john, mary-fred, julie-fred, ... - ...|...].
Run Code Online (Sandbox Code Playgroud)