Recursion 如何表达;“祖先”;递归地

Recursion 如何表达;“祖先”;递归地,recursion,prolog,transitive-closure,Recursion,Prolog,Transitive Closure,我被这个递归卡住了,它不像我期望的那样工作 我的错在哪里 #!/usr/bin/prolog % Facts mother( jeanne , michel ). % great-grandmother, grandfather mother( genevieve, aubin ). % grandmother, father mother( irene , alain ). % great-grandmother, grandfather mother( emilie

我被这个递归卡住了,它不像我期望的那样工作

我的错在哪里

#!/usr/bin/prolog

% Facts

mother( jeanne   , michel  ). % great-grandmother, grandfather
mother( genevieve, aubin   ). % grandmother, father
mother( irene    , alain   ). % great-grandmother, grandfather
mother( emilie   , colette ). % great-grandmother, grandmother
mother( colette  , muriel  ). % grandmother, mother
mother( muriel   , eve     ). % mother, daughter

father( joseph   , michel  ). % great-grandfather, grandfather
father( michel   , aubin   ). % grandfather, father
father( xxx      , alain   ). % great-grandfather, grandfather
father( marcel   , colette ). % great-grandfather, grandmother
father( alain    , muriel  ). % grandfather, mother
father( aubin    , eve     ). % father, daughter

% Rules

parent( Mother, Child ) :- mother( Mother, Child ).
parent( Father, Child ) :- father( Father, Child ).

ancestors( [Parent|Ancestors], Child ) :-
    parent( Parent, Child ),
    ancestors( Ancestors, Parent ).

% Queries

:-
    ancestors( Ancestor, eve ),
    format( 'Eve ancestors: ~w~n', Ancestor ).
% expected answer is [muriel, colette, alain, emilie, marcel, irene, xxx, aubin, michel, genevieve, joseph, jeanne]
编辑这是最终解决方案,谢谢大家

#!/usr/bin/prolog

/*##- Facts -##*/

mother( jeanne   , michel   ).
mother( genevieve, sylvie   ).
mother( genevieve, brigitte ).
mother( genevieve, aubin    ).
mother( irène    , alain    ).
mother( émilie   , colette  ).
mother( colette  , muriel   ).
mother( colette  , olivier  ).
mother( colette  , audrey   ).
mother( colette  , stéphane ).
mother( muriel   , eve      ).

father( joseph  , michel   ).
father( michel  , sylvie   ).
father( michel  , brigitte ).
father( michel  , aubin    ).
father( séraphin, alain    ).
father( marcel  , colette  ).
father( alain   , muriel   ).
father( alain   , olivier  ).
father( yves    , audrey   ).
father( yves    , stéphane ).
father( aubin   , eve      ).

/*##- Rules -##*/

parent( Mother, Child ) :- mother( Mother, Child ).
parent( Father, Child ) :- father( Father, Child ).

ancestor( Parent, Child ) :- parent( Parent, Child ).
ancestor( GrandParent, Child ) :-
    parent( GrandParent, Parent ),
    ancestor( Parent, Child ).

grandMothers( GrandMother, Child ) :-
    mother( GrandMother, FatherOrMother ),
    parent( FatherOrMother, Child ).

grandsFathers( GrandsFather, Child ) :-
    father( GrandsFather, FatherOrMother ),
    parent( FatherOrMother, Child ).

parents( Mother, Father, Child ) :-
    father( Father, Child ),
    mother( Mother, Child ).

strictSiblings( SisterOrBrother, Child ) :-
    parents( Mother, Father, Child ),
    parents( Mother, Father, SisterOrBrother ),
    SisterOrBrother \= Child.

siblings( SisterOrBrother, Child ) :-
    mother( Mother, Child ), mother( Mother, SisterOrBrother ), SisterOrBrother \= Child ;
    father( Father, Child ), father( Father, SisterOrBrother ), SisterOrBrother \= Child .

/*##- Queries -##*/

theMother :-
    mother( Mother, eve ),
    format( 'Ève\'s mother: ~w~n', [Mother] ).
theFather :-
    father( Father, eve ),
    format( 'Ève\'s father: ~w~n', [Father] ).
theParents :-
    setof( MotherOrFather, parent( MotherOrFather, eve ), MotherAndFather ),
    format( 'Ève\'s parents: ~w~n', [MotherAndFather] ).
theGrandMothers :-
    setof( GrandMother, grandMothers( GrandMother , eve ), GrandMothers ),
    format( 'Ève\'s grand-mothers: ~w~n', [GrandMothers] ).
theGrandFathers :-
    setof( GrandsFather, grandsFathers( GrandsFather , eve ), GrandsPères ),
    format( 'Ève\'s grand-fathers: ~w~n', [GrandsPères] ).
lesEnfants :-
    setof( Child, parents( genevieve, michel, Child ), Children ),
    format( 'Geneviève and Michel children: ~w~n', [Children] ).
theTwoParents :-
    parents( Mother, Father, eve ),
    format( 'Ève\'s mother and father: ~w, ~w~n', [Mother, Father] ).
theStrictSiblings :-
    setof( SisterOrBrother, strictSiblings( SisterOrBrother, muriel ), SistersAndBrothers ),
    format( 'Muriel\'s strict siblings: ~w~n', [SistersAndBrothers] ).
theSiblings :-
    setof( SisterOrBrother, siblings( SisterOrBrother, muriel ), SistersAndBrothers ),
    format( 'Muriel\'s siblings: ~w~n', [SistersAndBrothers] ).
theAncestors :-
    setof( Ancestor, ancestor( Ancestor, eve ), Ancestors ),
    format( 'Ève\'s ancestors: ~w~n', [Ancestors] ).
:-
    theMother,
    theFather,
    theParents,
    theGrandMothers,
    theGrandFathers,
    lesEnfants,
    theTwoParents,
    theStrictSiblings,
    theSiblings,
    theAncestors,
    halt( 0 ).
输出为:

Ève's mother: muriel
Ève's father: aubin
Ève's parents: [aubin,muriel]
Ève's grand-mothers: [colette,genevieve]
Ève's grand-fathers: [alain,michel]
Geneviève and Michel children: [aubin,brigitte,sylvie]
Ève's mother and father: muriel, aubin
Muriel's strict siblings: [olivier]
Muriel's siblings: [audrey,olivier,stéphane]
Ève's ancestors: [alain,aubin,colette,genevieve,irène,jeanne,joseph,marcel,michel,muriel,séraphin,émilie]

让我们以交互方式(在SWI Prolog中)执行此操作,而不是在脚本中使用
format/2
在最后打印答案

我们希望在列表中列出所有可能的
eve
祖先

所以我们必须

  • 在Prolog程序中查询目标的所有可能解决方案
    祖先(A,eve)
  • 然后将它们收集到一个列表中
  • 这是使用谓词
    bagof/3
    setof/3
    findall/3
    中的一个来完成的,该谓词回溯目标答案,并将一个变量与一个包含所有答案的列表相统一(对于
    bagof/3
    有重复答案,对于
    setof/3
    没有重复答案,以及“无可能答案”)产生
    []
    而不是
    findall/3
    的故障)

    所以我们只需要确保找到祖先的目标是正确的

    我们可以声明
    A
    C
    的祖先,如果

    • A
      C
      的父级;或
    • A
      是某些
      D
      的父代,
      D
      C
    (注意:只是“如果”,而不是“如果”只是“如果”。但是,假设没有其他方式可以使
    A
    成为
    C
    的祖先……这是一个合理的“封闭世界假设”)

    上面的公式非常适合Prolog的搜索策略,它试图首先解决正文中最左边的子目标:

    ancestor(A,C) :- parent(A,C).
    ancestor(A,C) :- parent(A,D),ancestor(D,C).
    
    以“检查左边的祖先”的方式进行:

    应该会产生相同的结果,但实际上不会:在最初给出正确答案后,Prolog处理器最终将进入一个无限循环,其中
    祖先(A,C)
    调用
    祖先(A,D)
    。(这将在更简单的“数据日志”语言中工作)

    不管怎样,我们结束了吗

    ?- ancestor(X,eve).
    X = muriel ;
    X = aubin ;
    X = jeanne ;
    X = genevieve ;
    X = irene ;
    X = emilie ;
    X = colette ;
    X = joseph ;
    X = michel ;
    X = xxx ;
    X = marcel ;
    X = alain ;
    false.
    
    现在将所有内容收集到列表中:

    (在SWI Prolog中,您必须说您希望打印长列表,而不是用省略号代替,所以):

    然后:

    ?- bagof(X,ancestor(X,eve),Out).
    Out = [muriel,aubin,jeanne,genevieve,irene,emilie,
           colette,joseph,michel,xxx,marcel,alain].
    

    在阅读本文之前,递归很容易,它可以帮助我们轻松找到解决方案。:)你刚刚忘记了递归的基本情况。我建议选择一个专门描述问题的标题。非常感谢,我已经将你的建议整合到我的样本(研究)中,并使用了很长的名称(我不喜欢a、C、D),并且对写祖先(祖父母、孩子)感到惊讶。我的错误就在这里。您的解决方案非常清晰。@Aubin近几个月来,我已从“长名称”切换到“短名称”,除非逻辑复杂且需要“就地文档”。之后更容易扫描源代码并找出变量。。。减少视觉噪音。由于变量总是子句局部的,所以在给定的上下文中没有那么多。(但我真的希望看到编辑器对变量着色的支持)。
    ?- set_prolog_flag(answer_write_options,[max_depth(0)]).
    true.
    
    ?- bagof(X,ancestor(X,eve),Out).
    Out = [muriel,aubin,jeanne,genevieve,irene,emilie,
           colette,joseph,michel,xxx,marcel,alain].