Prolog if else语法

时间:2015-07-21 03:17:16

标签: prolog zebra-puzzle

我似乎无法让我的if else声明发挥作用。

  1. John,Fred和Harry是男性,Mary,Julie,Susan和Anne是女性。
  2. John有金色头发,而Fred和Harry有黑头发。
  3. Julie和Susan是金发女郎,Mary和Anne是黑发女郎。
  4. Rich是每个拥有黄金的人 - 弗雷德和朱莉在我们的例子中。
  5. 男性只喜欢女性,反之亦然。此外,约翰和哈利喜欢富人,约翰喜欢金发,弗雷德喜欢黑发。
  6. 玛丽和朱莉都喜欢黑发人,朱莉同时喜欢富人。
  7. 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)).
    
    我想 (声明) - >(如果是,则运行此语句);(如果为false则运行此语句)。 是Prolog的正确方法。无论我为什么写

    ,为什么呢?
    likes(MaleName,FemaleName) 
    likes(FemaleName,MaleName)
    

    它返回true?

5 个答案:

答案 0 :(得分: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).

正如您可以计算的那样,这为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, _).

如果我们能够为每个 具有偏好的人提供一个条目,那就更好了,例如:

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。

  

如果某人有偏好,请检查候选人是否适合所有人; 否则成功。

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

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

或者,对于单向“喜欢”的列表,

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

答案 1 :(得分:1)

在提出问题之前,我会注意到您的代码中存在一些问题:

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

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

Prolog使用特定的&#39;编码&#39;逻辑公式,所谓的Horn clauses

  

它们在通过一阶分辨率证明的自动化定理中很重要,因为两个Horn子句的解决本身就是一个Horn子句,并且目标子句和明确子句的解决方案是一个目标子句。

关于问题的建模:我认为最大限度地减少“自然语言”之间的句法差异非常重要。公式和计算公式。每次更改都必须已调试: - )

那么,为什么不定义

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

你可以找到很多关于Zebra拼图的问题和答案,我在这里不再重复,所以请在Stack Overflow搜索框中查看[zebra-puzzle]。您将看到if/then/else从未被要求 - 有充分的理由。在Prolog中有更简单的方法来表达这些基本问题。

答案 2 :(得分: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 

//返回

答案 3 :(得分: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).

这样更好吗?

答案 4 :(得分: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) )
  .

它还允许性别灵活的喜欢 - 只需使用性别的匿名变量来表示不关心

这种做法的确伴随着喜欢单值的限制 - 没有方便的说法,例如,约翰喜欢红头发或金发,但不是棕色头发。