4

我似乎无法让我的 if else 语句起作用。

  1. 约翰、弗雷德和哈里是男性,玛丽、朱莉、苏珊和安妮是女性。
  2. 约翰有一头金发,而弗雷德和哈利有一头黑发。
  3. 朱莉和苏珊是金发女郎,玛丽和安妮是黑发女郎。
  4. Rich 是每个拥有黄金的人——在我们的例子中是 Fred 和 Julie。
  5. 男性只喜欢女性,反之亦然。此外,约翰和哈利喜欢有钱人,约翰喜欢金发女郎,弗雷德喜欢黑发女郎。
  6. 玛丽和朱莉都喜欢黑头发的人,朱莉同时也喜欢有钱人。
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)).

我认为(语句)->(如果为真,则运行此语句);(如果为假,则运行此语句)。在 Prolog 中是正确的方法。为什么不管我写什么

likes(MaleName,FemaleName) 
likes(FemaleName,MaleName)

它返回true?

4

5 回答 5

5

基于 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, ... - ...|...].
于 2015-07-21T09:24:12.253 回答
1

在转向您的问题之前,我会注意到您的代码中有几个问题:

关于语法p1 ; p2 :- p3.无效

?- [user].
p1;p2:-p3.
ERROR: user://1:9:
    No permission to modify static procedure `(;)/2'
    ...

Prolog 使用逻辑公式的特定“编码”,即所谓的Horn 子句

它们在通过一阶解析的自动定理证明中很重要,因为两个 Horn 子句的解析子本身就是一个 Horn 子句,而一个目标子句和一个确定子句的解析子是一个目标子句。

关于建模问题:我认为将“自然语言”公式和计算公式之间的句法差异最小化很重要。必须调试每个更改:-)

那么,为什么不定义

rich(Person) :- owns(Person, gold).
owns(fred, gold).
owns(julie, gold).

你可以找到很多关于斑马拼图的问题和答案,在此不再赘述,请查看[zebra-puzzle]Stack Overflow 搜索框。你会发现这if/then/else从来都不是必需的——有充分的理由。在 Prolog 中有更简单的方法来表达这些基本问题。

于 2015-07-21T05:43:21.033 回答
1

所以我修复了它,但现在我必须用你上面所说的来修改它。这种方式有效,但它似乎只得到第一个答案而不搜索另一个。示例:输出

1 ?- likes(julie,X).
X = harry ;
false.

节目编辑:

likes(male(X),female(Y)):-likes(X,Y).
likes(female(X),male(Y)):-likes(X,Y).
likes(X,Y):-
 ((X=julie)->
    ((hasdarkhair(Y))->
        (female(X), male(Y));
        male(X));

  ((X=julie)->
    ((isrich(Y))->
        (female(X), male(Y));
        male(X));

 ((X=mary)->
    ((hasdarkhair(Y))->
        (female(X), male(Y));
        male(X));
    female(X),male(Y))));

 ((X=john)->
    ((isrich(Y))->
        (male(X),   female(Y));
        female(X));
  ((X=john)->
    ((isblonde(Y))->
        (male(X),   female(Y));
        female(X));
 ((X=harry)->
    ((isrich(Y))->
        (male(X),   female(Y));
        female(X));
 ((X=fred)->
    ((hasbrunette(Y))->
        (male(X),   female(Y));
        female(X));
    male(X),female(Y))))).

什么时候应该返回

X=Harry
X=Fred

因为

likes(julie,fred)
true 

//返回

于 2015-07-21T07:57:33.447 回答
1

将代码更改为:

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(X,Y):-((X=julie),(hasdarkhair(Y);isrich(Y)),(female(X),male(Y))).
likes(X,Y):-((X=mary),hasdarkhair(Y),female(X),male(Y)).
likes(X,Y):-((X=john),(isrich(Y);hasblonde(Y)),male(X),female(Y)).
likes(X,Y):-((X=harry),isrich(Y),male(X),female(Y)).
likes(X,Y):-((X=fred),hasbrunette(Y),male(X),female(Y)).
likes(X,Y):-((X=susan);(X=anne)),((male(X),female(Y));(female(X),male(Y))).
    ownscar(john).
love(X,Y):-likes(X,Y),likes(Y,X).

那个更好吗?

于 2015-07-21T08:43:00.853 回答
0

我会通过定义一组人来解决这个问题,所有人都有一组必需的属性(性别、头发颜色和财务状况)和一组可选的喜欢(性别、头发颜色和财务状况)。我们将遵循约定,即匿名变量表示特定喜欢的无关_状态:

person( john  , is( male   , blonde   , poor ) , likes( female , blonde   , rich ) ) .
person( fred  , is( male   , brunette , rich ) , likes( female , brunette , _    ) ) .
person( harry , is( male   , brunette , poor ) , likes( female , _        , rich ) ) .

person( mary  , is( female , brunette , poor ) , likes( male   , brunette , _    ) ) .
person( julie , is( female , blonde   , rich ) , likes( male   , brunette , rich ) ) .
person( susan , is( female , blonde   , poor ) , likes( male   , _        , _    ) ) .
person( anne  , is( female , brunette , poor ) , likes( male   , _        , _    ) ) .

这使您可以非常简单地确定景点是否存在:

likes( P1 , P2 ) :-
  person( P1 , _            , likes(G2,H2,S2) ) ,
  person( P2 , is(G2,H2,S2) , _               )
  .

如果你想表现出相互吸引,你可以简单地扩展一下:

mutual_attraction( P1 , P2 ) :-
  person( P1 , is(G1,H1,S1) , likes(G2,H2,S2) ) ,
  person( P2 , is(G2,H2,S2) , likes(G1,H1,S1) )
  .

它还允许性别灵活的喜欢 - 只需使用性别的匿名变量来表示don't care

这种方法确实有一个限制,喜欢是单值的——例如,没有方便的方法可以说 john 喜欢红头发或金发,但不喜欢棕色头发。

于 2015-07-22T00:18:35.300 回答