list - 在 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.
推荐阅读
- php - 数据未显示在 jquery DataTable 中
- java - 文件通配符使用 *
- android - Android DialogFlow V2 SDK Java 客户端库 Grpc Google Cloud Platform 从实时音频流中检测意图
- mongodb - MongoDB 关闭并显示代码:12
- feathersjs - 在羽毛钩子中获取内容类型
- neo4j - 当数据库为空时,ANY 函数不返回任何内容
- html - Ng-Show 无法正常工作
- microsoft-graph-api - 检测和获取嵌套组的成员
- angular - 如何在 *ngIf 中实现比较器编号
- java - Swing JList SetCellRenderer 背景颜色不起作用