首页 文章

Prolog - 对称谓词

提问于
浏览
3

我必须在prolog中模拟家谱 . 我有对称谓词的问题 . Facts:

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

Rules:

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, joh):yes 
blood_relation(john,johns_father): no

所以..有办法解决这个问题 . 我需要查询:所有不在blood_relation中的对..

更新:

第一个声明应该满足哪种关系? blood_relation(X,Y): - blood_relation(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.

工作得很好

3 回答

  • 8

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

    大多数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]).
    

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

  • 0

    使特定谓词对称的天真解决方案并不是一个体面的解决方案 . 为了一般性,让我们看一下友情关系,这样人们就不会被舅舅等绊倒 .

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

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

    你最初会想到像“ friends(A,B) :- friends(B,A). " would fix things right up, but this leads you to infinite recursion because it tells prolog that if it just swaps the argument one more time it might just work. There is a predicate called " @</2 " that tells you whether one term (even a variable) comes before another in the "标准的术语顺序”这样的规则 . 技术含义在这里并不是那么重要,但我们关心的是,对于两个不同的术语,它们只适用于它们的一个顺序 . 我们可以用它来打破无限递归!

    这条单一规则将使“ 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).
    
  • 1

    第一个声明应该满足什么样的关系?

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

    这并没有告诉你任何你还没有“知道”的东西,并且会让你感到头痛 . 至于“不”的答案,看起来你已经从查询中获得了所有答案,并且解释器只是告诉你已经没有了 .

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

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

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

    并问问自己为什么会这样!

相关问题