基于 CapelliC 的回答,因为显然他的回答不够明确。至于 if-else 语法和用法,请参阅答案的末尾。
首先,您的问题陈述中包含的信息是您希望以 Prolog 程序的形式表示的信息。在 Prolog 中,您有谓词,它可以描述它们的论点之间的关系,或者陈述关于它们的论点的已知事实。例如,这是一个事实表;它指出我们知道存在七个人:
人(约翰)。
人(弗雷德)。
人(哈利)。
人(玛丽)。
人(朱莉)。
人(苏珊)。
人(安妮)。
好的。我们现在要声明其中一些是男性,一些是女性。
% John、Fred 和 Harry 是男性,Mary、Julie、Susan 和 Anne 是女性。
男(约翰)。
男性(弗雷德)。
男(哈利)。
女(玛丽)。
女(朱莉)。
女(苏珊)。
女(安妮)。
这是另外两个事实表。现在您想将有关他们头发颜色的信息添加到您的数据库中:
%约翰的头发是金色的,而弗雷德和哈利的头发是深色的。
%朱莉和苏珊是金发女郎,玛丽和安妮是黑发女郎。
person_hair(约翰,金发)。
person_hair(弗雷德,黑暗)。
person_hair(哈利,黑暗)。
person_hair(朱莉,金发)。
person_hair(苏珊,金发)。
person_hair(玛丽,黑暗)。
person_hair(安妮,黑暗)。
如果您愿意,这是一个包含两列的表格:第一列是人,第二列是头发颜色的描述。“布鲁内特”这个词通常用来形容一个黑头发的女人,所以我们可以添加一条规则,说明:
%黑发是黑头发的女性
黑发(X):-
女性(X),
人头发(X,深色)。
我们有一些人拥有黄金,而在我们的计划中拥有黄金会使一个人变得富有:
person_owns(弗雷德,金)。
person_owns(朱莉,金)。
is_rich(X) :-
%人(X),
个人拥有(X,金)。
在我们严格的异性恋项目中,男人喜欢女人,女人喜欢男人:
person_likes(M, F) :-
男(男),
女(女)。
person_likes(F, M) :-
女(女),
男(男)。
正如您可以计算的那样,这为我们提供了 3 x 4 + 4 x 3 = 24 种可能的解决方案,person_likes(A, B)
而没有任何进一步的限制:
?- bagof(AB,person_likes(A,B),R),长度(R,Len)。
R = [约翰-玛丽,约翰-朱莉,约翰-苏珊,约翰-安妮,弗雷德-玛丽,弗雷德-朱莉,弗雷德-苏珊,弗雷德-安妮,... - ...|...],
莱恩 = 24。
这是一个非常普遍的规则:它描述了自由变量之间的关系,这使得它与我们的关系有些不同person_owns/2
,例如。它真的有用吗?为什么不:
is_heterosexual(H) :-
人(H)。
但这只是说明我们计划中的每个人都是异性恋;它不能让我们得出异性恋是喜欢异性的人的规则。也许重新命名它会更好,以更好地表达它的含义(我将使用 if-then-else 结构来展示它通常是如何完成的):
对立性别(X,Y):-
(男(X)
-> 女性(Y)
; 女(X)
-> 男(Y)
)。
为了我们的目的,这可能和上面写的一样好:
对立性别(男,女):-
男(男),女(女)。
对立性别(F,M):-
男(男),女(女)。
有了这个,我们可以编写一个person_likes/2
带有一般前提条件的规则,即对方必须是异性:
人喜欢(X,Y):-
相反的性别(X,Y),
适合个人口味(X,Y)。
我们现在可以为每个人的个人口味制定规则。对于朱莉:
适合个人口味(朱莉,X):-
is_rich(X),
人头发(X,深色)。
然而,这会产生一个小问题。您需要确保对于程序知道的每个人,此表格中都有一条规则。我们不知道 Anne 有什么偏好,所以我们必须有一个规则:
%任何人(男性)都适合安妮的口味
适合个人品味(安妮,_)。
如果我们可以改为有一个表,其中包含每个具有偏好的人的条目,那就更好了,例如:
person_preferences(julie, [is_rich, person_hair(dark)])。
个人偏好(哈利,[is_rich])。
% 等等
这将允许我们编写fits_personal_taste/2
如下内容:
适合个人口味(X,Y):-
( person_preferences(X, Ps)
-> maplist(fits_preference(Y), Ps)
; 真的
)。
这是Prolog 中 if-else 构造的预期用途:异或。
如果一个人有偏好,请检查候选人是否适合所有偏好;否则成功。
会是什么样fits_preference/2
子呢?它将一个人作为第一个参数,一个在第二个参数中具有偏好的术语,并且必须以某种方式检查该人是否满足该偏好。一个有点 hacky 的解决方案是使用所谓的 Univ 运算符=..
来获取 form 的一个术语person_hair(Color)
,创建一个form 的术语person_hair(Person, Color)
,然后调用它:
fits_preference(Person, Preference) :-
Preference =.. [F|Args],
Preference1 =.. [F,Person|Args],
call(Preference1).
person_preferences
将一个人直接映射到可调用术语可能会更好:
person_preferences(julie, P, [is_rich(P), person_hair(P, dark)])。
个人偏好(哈利,P,[is_rich(P)])。
% 等等
有了这个,fits_personal_taste/2
就变成了:
适合个人口味(X,Y):-
( person_preferences(X, Y, Ps)
-> 地图列表(呼叫,Ps)
; 真的
)。
当person_preferences/3
在语句的条件部分调用时,偏好列表中的每个偏好都绑定到一个具体的人;然后我们打电话给每个人来检查它是否可以证明我们程序中的事实是真实的。
最后,一个辅助谓词possible_pair/2
表明两个人都需要彼此喜欢:
possible_pair(X, Y) :-
person_likes(X, Y),
person_likes(Y, X),
X @< Y.
最后一行将通过假设两个人应该有严格的顺序来确保我们不会两次得到同一对。
有了这个,我得到:
?- bagof(A-B, possible_pair(A, B), R).
R = [fred-mary, anne-fred].
或者,对于单向“喜欢”列表,
?- 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, ... - ...|...].