2015-07-21 63 views
4

我似乎无法让我的if语句工作。序言如果其他语法

  1. 约翰,弗雷德和哈利是男人,玛丽,朱莉,苏珊和安妮是女人。
  2. 约翰有金色的头发,而弗雷德和哈利有黑发。
  3. 朱莉和苏珊是金发女郎,玛丽和安妮是黑发。
  4. Rich是每个拥有黄金的人 - 弗雷德和朱莉在我们的例子中。
  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?

回答

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×4 + 4×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). 

我们c现在制定每个人的个人品味规则。朱丽:

 
fits_personal_taste(julie, X) :- 
    is_rich(X), 
    person_hair(X, dark). 

然而,这产生了一个小问题。你需要确保对于程序知道的每个人约这里有一个规则。我们不知道安妮任何偏好,所以我们必须有一个规则:

 
% 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专有 OR中的if-else构建的预期用途。

如果一个人的喜好,检查候选人符合所有的人; 否则成功。

fits_preference/2怎么样?这将需要一个人作为第一个参数,第二个参数是首选项,并且必须以某种方式检查该人是否符合该首选项。一个有点哈克的解决办法是使用所谓的大学运营商=..采取的形式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

这太好了。我的程序已经完美运行,但这个组织太好了,无法通过。我会再次重新设计它。感谢您的澄清。 – SuperCell

+3

我没有15点的声望可以投票,但是当我这样做时,我会回到这里。 – SuperCell

+0

安全检查的参数如何“充分实例化”? – false

1

你的问题之前,方向盘,我想指出,有几个问题,在您的代码:

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

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

Prolog使用逻辑公式的具体的“编码”,所谓Horn clauses

他们在自动定理的一阶分辨率证明很重要,因为有两个Horn子句的解决方法本身是一个霍恩条款,以及目标条款和明确条款的解决方案是一个目标条款。

关于对问题进行建模:我认为最小化“自然语言”公式和计算公式之间的语法差异非常重要。每一个变化必须调试 :-)

那么,为什么不来定义

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

您可以找到有关Zebra拼图许多问题和答案,我就不在这里赘述了,所以请期待[zebra-puzzle]在堆栈溢出搜索框。你会看到if/then/else从不需要 - 有很好的理由。在Prolog中有更简单的方法来表达这些基本问题。

+1

好答案(+1)。顺便说一句,这甚至不像“斑马谜题”那样的问题,它更多的是寻找正确的方式来模拟数据,就像事实是什么,规则是什么一样。你用'rich/1'和'拥有/ 1'的例子是对的。 – 2015-07-21 07:11:11

+1

您可以在语法中嵌入标签:'[tag:zebra-puzzle]' – mat

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 

//返回

+0

如果/ then/else'operator'已经被引入*为了避免替代方案出现,Prolog默认会执行。也许,将Prolog看作比原子值更丰富的域上的“可编程”SQL ... – CapelliC

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

是不是更好?

+0

但是我使用分号作为或语句来保存不必重复的代码。你能举一个例子,说明哪里可以做得更好吗? – SuperCell

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

这人所以允许性别灵活的喜欢—只是使用匿名变量为性别来表示不在乎

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

+0

这也是一个很好的方法来处理它(+1)。不同之处在于,您不会“正常化”数据,但您明确描述了该方法的优点和缺点。 – 2015-07-22 06:04:58