簡體   English   中英

在 Prolog 中遞歸創建后代列表

[英]Recursively creating a list of descendants in Prolog

我對 Prolog 真的很陌生,並且正在努力遞歸地附加到列表中。 我正在嘗試創建一個程序,告訴您一個人是否是另一個人的后代,以及他們之間的后代列表。 例如,示例數據和所需的輸出:

parent(greatgrandma, grandma).
parent(grandma, mom).
parent(mom, daughter).

?- relatives(greatgrandma, daughter, Lineage).
Lineage = [greatgrandma, grandma, mom, daughter]

?- relatives(mom, son, Lineage).
False.

我能夠遞歸搜索以檢查兩個人是否與以下代碼相關,並將其作為測試基礎案例...

relatives(X, Y, Lineage):- isChild(X,Y, Lineage).
isChild(X,Y, Lineage):- parent(X,Y), append([X], [Y], Lineage).
isChild(X,Y, Lineage):- parent(X,Z), isChild(Z,Y, Lineage).

但是到目前為止我嘗試從這個后代搜索中建立一個列表的一切都沒有奏效。 這是我得到的最接近的:

relatives(X, Y, Lineage):- append([X], Lineage, NewLineage), isChild(X,Y, NewLineage).
isChild(X,Y, Lineage):- parent(X,Z), append(Lineage, [Z], NewLineage), isChild(Z,Y, NewLineage).
isChild(X,Y, Lineage):- parent(X,Y), append(Lineage, [Y], NewLineage).
[trace]  ?- relatives(grandma, daughter, P).
   Call: (10) relatives(grandma, daughter, _12442) ? creep
   Call: (11) lists:append([grandma], _12442, _12904) ? creep
   Exit: (11) lists:append([grandma], _12442, [grandma|_12442]) ? creep
   Call: (11) isChild(grandma, daughter, [grandma|_12442]) ? creep
   Call: (12) parent(grandma, _13040) ? creep
   Exit: (12) parent(grandma, mom) ? creep
   Call: (12) lists:append([grandma|_12442], [mom], _13136) ? creep
   Exit: (12) lists:append([grandma], [mom], [grandma, mom]) ? creep
   Call: (12) isChild(mom, daughter, [grandma, mom]) ? creep
   Call: (13) parent(mom, _13272) ? creep
   Exit: (13) parent(mom, daughter) ? creep
   Call: (13) lists:append([grandma, mom], [daughter], _13368) ? creep
   Exit: (13) lists:append([grandma, mom], [daughter], [grandma, mom, daughter]) ? creep
   Call: (13) isChild(daughter, daughter, [grandma, mom, daughter]) ? creep
   Call: (14) parent(daughter, _13510) ? creep
   Fail: (14) parent(daughter, _13554) ? creep
   Redo: (13) isChild(daughter, daughter, [grandma, mom, daughter]) ? creep
   Call: (14) parent(daughter, daughter) ? creep
   Fail: (14) parent(daughter, daughter) ? creep
   Fail: (13) isChild(daughter, daughter, [grandma, mom, daughter]) ? creep
   Redo: (12) isChild(mom, daughter, [grandma, mom]) ? creep
   Call: (13) parent(mom, daughter) ? creep
   Exit: (13) parent(mom, daughter) ? creep
   Call: (13) lists:append([grandma, mom], [daughter], _13914) ? creep
   Exit: (13) lists:append([grandma, mom], [daughter], [grandma, mom, daughter]) ? creep
   Exit: (12) isChild(mom, daughter, [grandma, mom]) ? creep
   Exit: (11) isChild(grandma, daughter, [grandma]) ? creep
   Exit: (10) relatives(grandma, daughter, []) ? creep
P = [] .

因此,我按照 [奶奶、媽媽、女兒] 的正確順序獲取列表,但我不知道如何返回 P 的值而不是空列表。 此外,使用“son”的測試會導致使用此代碼的無限遞歸循環,但不會使用之前的基本情況。

任何幫助或建議將不勝感激。

你很接近! 如果你想采用這種方法,缺少的主要是以下觀察:如果isChild既接受“當前世系”並預計產生“新世系”,那么它需要兩個世系參數。 一種用於“舊”狀態,一種用於“新”狀態。

像這樣:

isChild(X,Y, Lineage, NewLineage) :-
    parent(X,Z),
    append(Lineage, [Z], Lineage2),
    isChild(Z,Y, Lineage2, NewLineage).
isChild(X,Y, Lineage, NewLineage) :-
    parent(X,Y),
    append(Lineage, [Y], NewLineage).

當您調用它時,您需要傳入正確的初始世系以開始:

relatives(X, Y, Lineage) :-
    isChild(X,Y, [X], Lineage).

這現在表現得像你想要的:

?- relatives(grandma, daughter, Lineage).
Lineage = [grandma, mom, daughter] ;
false.

?- relatives(mom, son, Lineage).
false.

然而,真正的答案是,在 Prolog 中進行此類搜索時,通常不會將內容附加到列表中。 相反,您預先准備了數據。 這更有效,也更短,更易讀,中間狀態更少:

ancestor_successor_lineage(Ancestor, Successor, [Ancestor, Successor]) :-
    parent(Ancestor, Successor).
ancestor_successor_lineage(Ancestor, Successor, [Ancestor | Lineage]) :-
    parent(Ancestor, Intermediate),
    ancestor_successor_lineage(Intermediate, Successor, Lineage).

請注意,如果您對血統不感興趣,這與您編寫的內容基本相同。 添加中間狀態的記錄只是添加一個(不是兩個,像以前一樣!)額外的參數和列表構造函數的使用[_ | _] [_ | _]parent的“單步”與遞歸步驟中的列表結合起來。 這確實是在 Prolog 中編寫它的首選方式。

這與其他解決方案的行為相同:

?- ancestor_successor_lineage(grandma, daughter, Lineage).
Lineage = [grandma, mom, daughter] ;
false.

?- ancestor_successor_lineage(mom, son, Lineage).
false.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM