3

我必须在 prolog 中模拟家谱。我有对称谓词的问题。 事实:

parent(x,y).
male(x).
female(y).
age(x, number).

规则:

blood_relation让我头疼。这就是我所做的:

blood_relation(X,Y) :- ancestor(X,Y).
blood_relation(X,Y) :- uncle(X,Y)
                    ; brother(X,Y)
                    ; sister(X,Y)
                    ; (mother(Z,Y),sister(X,Z))
                    ; (father(Z,Y),sister(X,Z))
                    ; (father(Z,Y),brother(X,Z)).
blood_relation(X,Y) :- uncle(X,Z)
                    , blood_relation(Z,Y).

我得到了我认为令人满意的结果(我有双重打印 - 我可以解决这个问题),问题是我希望这种关系是对称的。现在不是。

blood_relation(johns_father, john):yes 
blood_relation(john,johns_father): no

所以..有没有办法解决这个问题。我需要查询:所有不在血缘关系中的对..

更新:

第一个陈述应该满足什么样的关系?血液关系(X,Y):-血液关系(X,Y)。

对不起..这是一个糟糕的复制/粘贴..它

blood_relation(X,Y):-ancestor(X,Y).

现在固定在上面。

以下是其他规则:

father(X,Y) :-
  parent(X,Y),male(X).  
mother(X,Y) :-
  parent(X,Y),female(X).  
brother(X,Y) :-
  parent(Z,X),parent(Z,Y),
  male(X).  
sister(X,Y) :-
  parent(Z,X),parent(Z,Y),
  female(X).  
grandFather(X,Y) :-
  parent(Z,Y),parent(X,Z),
  male(X).  
grandMother(X,Y) :-
  parent(Z,Y),
  parent(X,Z),female(X).  
uncle(X,Y) :-
  mother(Z,Y),brother(X,Z).  
ancestor(X,Y) :-
  ancestor(X,Y).  
ancestor(X,Y) :-
  parent(X,Z),ancestor(Z,Y).

母亲的兄弟在叔叔的定义中。这有点奇怪。我有需要实施的规则,除此之外我不知道如何实施规则。我只是困惑。

知道如何制作blood_relation对称吗?并且not_blood_relation是新规则。我需要查询。这个真的让我很头疼。也许是因为关系写得像废话。

而且没有更多的事实。就这样。所有规则,所有事实。

查询..not(blood_relation(X,Y))不起作用,我真的不知道为什么。例如查询:

age(X,Y), Y>18,  
not(parent(X,Z)),write(X),nl,fail.

工作得很好

4

3 回答 3

12

使特定谓词对称的天真的解决方案与一个体面的解决方案相差不远。为了概括起见,让我们看一下友谊关系,这样人们就不会被叔叔之类的人绊倒。

以下是一些详细说明友谊关系的事实(例如,数字是用户 ID,参数的特定顺序来自谁发起了友谊)。

friends(1,2).
friends(5,2).
friends(7,4).

您最初会认为像 " friends(A,B) :- friends(B,A)." 这样的规则可以解决问题,但这会导致无限递归,因为它告诉 prolog 如果它只是再交换一次参数,它可能会起作用。有一个谓词“ @</2”,它告诉您一个术语(甚至是一个变量)是否以“术语的标准顺序”出现在另一个之前。技术含义在这里并不是那么重要,但我们关心的是,对于两个不同的术语,它只对它们的一个排序是正确的。我们可以用它来打破无限递归!

这条规则将负责使“ friend/2”对称。

friends(A,B) :- A @< B, friends(B,A).

尽管这很简洁,但您应该为大型项目采用一种方法。回想一下,我的事实列表中 args 的顺序有一些实际意义(谁发起了友谊)。添加最终规则破坏了未来对该信息的访问,并且对于阅读代码的其他人来说,将对称属性隐藏在一行代码中,这在面对硬编码数据块时很容易被忽略。

考虑工业级解决方案:

friended(1,2).
friended(5,2).
friended(7,4).

friends(A,B) :- friended(A,B).
friends(A,B) :- friended(B,A).

它比较笨重,但它在不使用晦涩的谓词的情况下清晰地读取并保留了原始信息(有一天您可能会在实际应用程序中再次需要这些信息)。

--

至于查找具有特定属性的对,请确保在使用否定查找实际个体时始终包含一些谓词以在规则中提供上下文。

potential_enemies(A,B) :- user(A), user(B), \+ friends(A,B).
于 2009-04-30T02:50:27.980 回答
1

有点像家庭作业,不是吗...

大多数 prolog 初学者都没有想到的一个技巧是列表模式匹配。考虑像 [a1,[[a2],[b2,[[e3],[f3]]],[c2]]] 这样的树,如<tree>=[root,[ <tree1>, <tree2>,...]]:

%Y is immediate child of X?
child(X,Y,[X|S]) :- member([Y|_],S).

%pick one tree in S and check
child(X,Y,[X|S]) :- member([Z|SS],S),child(Z,Y,[Z|SS]).

%X and Y end up with same root?
sib(X,Y,[R|T]) :- child(R,X,[R|T]), child(R,Y,[R|T]).

我认为你可以改进这一点,使用对作为根,添加性别,为树成员的特定关系命名......

于 2009-04-27T00:29:36.597 回答
0

第一个陈述应该满足什么样的关系?

blood_relation(X,Y):-blood_relation(X,Y).

这并没有告诉你任何你还不“知道”的东西,并且会导致你递归头痛。至于“否”的答案,看起来您已经从要获得的查询中获得了所有答案,而解释器只是告诉您没有更多答案。

你真的应该发布更多的事实,以及 uncle/2 的定义,你有没有理由不匹配母亲的兄弟,只是她的妹妹?您还有很多其他问题需要解决:-)。

对于不是血缘关系的一切,试试这个:

not_blood_relation(X, Y) :- blood_relation(X, Y), !, fail.
not_blood_relation(X, Y).

并问自己为什么它有效!

于 2009-04-27T00:33:50.767 回答