Prolog if else 语法

Prolog if else syntax

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

  1. 约翰、弗雷德和哈利是男性,玛丽、朱莉、苏珊和安妮是女性。
  2. 约翰是金发,而弗雷德和哈利是黑发。
  3. 朱莉和苏珊是金发女郎,玛丽和安妮是美女运行。
  4. 富人是每个拥有黄金的人——在我们的例子中是弗雷德和朱莉。
  5. 男性只喜欢女性,反之亦然。而且,John和Harry喜欢有钱人,John喜欢金发女郎,Fred喜欢b运行ette。
  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)

它returns是真的吗?

在回答您的问题之前,我注意到您的代码中存在几个问题:

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

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

Prolog 使用特定的 'encoding' 逻辑公式,即所谓的 Horn clauses

They are important in automated theorem proving by first-order resolution, because the resolvent of two Horn clauses is itself a Horn clause, and the resolvent of a goal clause and a definite clause is a goal clause.

关于问题建模:我认为尽量减少 'natural language' 公式和计算公式之间的句法差异很重要。每个更改都必须 debugged :-)

所以,为什么不定义

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

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

所以我修复了它,但现在我必须根据您上面所说的重新修改它。这种方式有效,但它似乎只得到第一个答案而没有搜索另一个。 例子: 输出

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))))).

什么时候应该 return

X=Harry
X=Fred

因为

likes(julie,fred)
true 

//returns

将代码更改为:

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).

这样更好吗?

基于 CapelliC 的回答,因为显然他的回答不够明确。至于if-else的语法和使用,见答案末尾。

首先,问题陈述中的信息是您希望以 Prolog 程序的形式表示的信息。在 Prolog 中,你有 谓词,它可以描述它们的论点之间的 关系,或者陈述已知的 真相 关于他们的论据。例如,这是一个 table 的事实;它说我们知道有七个人存在:

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).

还有两个 table 事实。现在您想将有关他们头发颜色的信息添加到您的数据库中:

% 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).

如果您愿意,这是一个包含两栏的 table:第一栏是人物,第二栏是对头发颜色的描述。 "brunette" 这个词通常用来描述一个黑头发的 女人 ,所以我们可以添加一个 规则 来说明:

% 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).

正如您可以计算的那样,这为 person_likes(A, B) 提供了 3 x 4 + 4 x 3 = 24 种可能的解决方案,没有任何进一步的限制:

?- 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, _).

如果我们可以用一个 table 为每个 有偏好的人添加一个条目,那就更好了,例如:

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 结构的预期用途:独占 OR。

If a person has preferences, check if the candidate fits all of them; otherwise succeed.

fits_preference/2 会是什么样子?它会把一个人作为第一个参数,一个在第二个参数中带有偏好的术语,并且必须以某种方式检查那个人的偏好是否得到满足。一个有点棘手的解决方案是使用所谓的 Univ 运算符 =.. 来获取形式为 person_hair(Color) 的项,生成形式为 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)]).
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.

最后一行将通过假设两个人应该严格遵守顺序来确保我们不会两次得到同一对。

有了这个,我得到:

?- bagof(A-B, possible_pair(A, B), R).
R = [fred-mary, anne-fred].

或者,对于单向列表"likes",

?- 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, ... - ...|...].

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

指示
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) )
  .

它还允许性别灵活的点赞——只需使用性别的匿名变量来表示不关心

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