Prolog递归累加器
Prolog recursive accumulator
我正在尝试为大学课程制作一个知识库。具体来说,现在我正在尝试制作一个累加器,它将参加一门课程并提供必须首先参加的所有 类 的列表,即课程的先决条件,这些先决条件的先决条件等... Based on this chart.
这里有一个谓词示例:
prereq(cst250, cst126).
prereq(cst223, cst126).
prereq(cst126, cst116).
prereq(cst105, cst102).
prereq(cst250, cst130).
prereq(cst131, cst130).
prereq(cst130, cst162).
prereq(anth452, wri122).
prereq(hist452, wri122).
这是我对累加器的尝试:
prereq_chain(Course, PrereqChain):-
%Get the list of prereqs for Course
findall(Prereq, prereq(Course, Prereq), Prereqs),
%Recursive call to all prereqs in X
forall(member(X, Prereqs),
(prereq_chain(X, Y),
%Combine current layer prereqs with deeper
append(Prereqs, Y, Z))),
%Return PrereqChain
PrereqChain = Z.
所需的查询输出为:
?- prereq_chain(cst250, PrereqList).
PrereqList = [cst116, cst126, cst162, cst130]
相反,我得到了 true 的答案,以及关于 Z 是单身人士的警告。
我看过 other posts 询问过类似的问题,但他们都有单通道的向后遍历,而我的解决方案需要多通道。
提前感谢您的指导。
使用 forall/2
的问题是它不建立绑定。看看这个人为的例子:
?- forall(member(X, [1,2,3]), append(['hi'], X, R)).
true.
如果 forall/2
为 X 或 R 建立了绑定,它将出现在结果中;相反,我们只是得到 true
因为它成功了。因此,您需要使用的构造不仅 运行 一些计算,而且会产生一个值。在这种情况下,您想要的是 maplist/3
,它采用目标和参数列表并构建更大的目标,返回结果。输入下面的解决方案后,您将能够在您的控制台中看到效果。
?- maplist(prereq_chain, [cst126, cst130], X).
X = [[cst116], [cst162]].
所以这得到了列表中两个 类 的先决条件列表,但给了我们一个列表列表。这是 append/2
派上用场的地方,因为它本质上是扁平化列表列表:
?- append([[cst116], [cst162]], X).
X = [cst116, cst162].
这是我想出的解决方案:
prereq_chain(Class, Prereqs) :-
findall(Prereq, prereq(Class, Prereq), TopPrereqs),
maplist(prereq_chain, TopPrereqs, MorePrereqs),
append([TopPrereqs|MorePrereqs], Prereqs).
我正在尝试为大学课程制作一个知识库。具体来说,现在我正在尝试制作一个累加器,它将参加一门课程并提供必须首先参加的所有 类 的列表,即课程的先决条件,这些先决条件的先决条件等... Based on this chart.
这里有一个谓词示例:
prereq(cst250, cst126).
prereq(cst223, cst126).
prereq(cst126, cst116).
prereq(cst105, cst102).
prereq(cst250, cst130).
prereq(cst131, cst130).
prereq(cst130, cst162).
prereq(anth452, wri122).
prereq(hist452, wri122).
这是我对累加器的尝试:
prereq_chain(Course, PrereqChain):-
%Get the list of prereqs for Course
findall(Prereq, prereq(Course, Prereq), Prereqs),
%Recursive call to all prereqs in X
forall(member(X, Prereqs),
(prereq_chain(X, Y),
%Combine current layer prereqs with deeper
append(Prereqs, Y, Z))),
%Return PrereqChain
PrereqChain = Z.
所需的查询输出为:
?- prereq_chain(cst250, PrereqList).
PrereqList = [cst116, cst126, cst162, cst130]
相反,我得到了 true 的答案,以及关于 Z 是单身人士的警告。
我看过 other posts 询问过类似的问题,但他们都有单通道的向后遍历,而我的解决方案需要多通道。
提前感谢您的指导。
使用 forall/2
的问题是它不建立绑定。看看这个人为的例子:
?- forall(member(X, [1,2,3]), append(['hi'], X, R)).
true.
如果 forall/2
为 X 或 R 建立了绑定,它将出现在结果中;相反,我们只是得到 true
因为它成功了。因此,您需要使用的构造不仅 运行 一些计算,而且会产生一个值。在这种情况下,您想要的是 maplist/3
,它采用目标和参数列表并构建更大的目标,返回结果。输入下面的解决方案后,您将能够在您的控制台中看到效果。
?- maplist(prereq_chain, [cst126, cst130], X).
X = [[cst116], [cst162]].
所以这得到了列表中两个 类 的先决条件列表,但给了我们一个列表列表。这是 append/2
派上用场的地方,因为它本质上是扁平化列表列表:
?- append([[cst116], [cst162]], X).
X = [cst116, cst162].
这是我想出的解决方案:
prereq_chain(Class, Prereqs) :-
findall(Prereq, prereq(Class, Prereq), TopPrereqs),
maplist(prereq_chain, TopPrereqs, MorePrereqs),
append([TopPrereqs|MorePrereqs], Prereqs).