Prolog - 递归地将数字附加到列表中



我刚刚开始学习Prolog,而且我在理解递归概念时遇到了麻烦。现在,仅仅为了练习,我正在尝试编写一个程序,将10个数字附加到列表中,然后打印出该列表。

该程序的自我强加规则是,列表必须在主谓词中"声明"(我不确定这是否是Prolog的正确词),主谓词调用另一个谓词将数字附加到列表中。

这就是我目前所拥有的,我知道它行不通,因为我试图在addToList谓词的末尾重新定义List,这在语言中是不允许的。

% Entry point that declares a list (`List`) to store the 10 numbers
printList(List) :-
addToList(0, List),
writeln(List).
% Base case - once we hit 11 we can stop adding numbers to the list
addToList(11, _).
% First case - this predicate makes adding the first number easier for me...
addToList(0, List) :-
append([], [0], NewList),
addToList(1, NewList),
append([],  NewList, List). % This is valid, but List will just be [0] I think..
% Cases 1-10
addToList(Value, List) :-
append(List, [Value], NewList),
NextVal is Value+1,
addToList(NextVal, NewList),
append([], NewList, List). % This is INVALID since List is already defined

该计划将从以下位置开始:

printList(List).

有没有一种简单的方法可以更改我编写的损坏的程序以使其正常工作?我对如何获取存储在List中的数字感到非常迷茫。

你在程序上思考,在prolog中你不能改变变量。您正在尝试自己构建列表。在prolog风格中,您尝试声明所需列表的约束。如果nlist/2是一个给出 N 个数字列表的谓词,那么它的属性到底是什么?nlist(0, []).,如果nlist(N, Xs),则nlist(N+1, [N+1 | Xs]).所以你只需写这些,让prolog负责建设。

nlist(0, []).
nlist(N, [N | Xs]) :-
N>0, N1 is N-1,
nlist(N1, Xs).

如果您对递归调用的发生方式感到困惑,请尝试使用trace/0trace/1。您可以在以下跟踪中查看调用是如何完成的。您可以通过调用trace(nlist)来获得此内容。

?- nlist(3, X).
T Call: nlist(3, _78)
T Call: nlist(2, _902)
T Call: nlist(1, _1464)
T Call: nlist(0, _2026)
T Exit: nlist(0, [])
T Exit: nlist(1, [1])
T Exit: nlist(2, [2, 1])
T Exit: nlist(3, [3, 2, 1])
X = [3, 2, 1]

更程序化的样式代码如下

addToList(11, A, A).
% Cases 1-10
addToList(Value, List, NewList) :-
Value < 11,  append(List, [Value], Temp),
NextVal is Value+1,
addToList(NextVal, Temp, NewList).

这给出了中间参数是累加器。当你达到11时,累加器就是答案。

?- addToList(1, [], X).
X = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] 
?- addToList(5, [], X).
X = [5, 6, 7, 8, 9, 10] 

查看样本迹线以及它们在nlistaddToList方面的区别。尝试找出差异以及为什么会发生差异。

?- addToList(7, [], X).
T Call: addToList(7, [], _33565254)
T Call: addToList(8, [7], _33565254)
T Call: addToList(9, [7, 8], _33565254)
T Call: addToList(10, [7, 8, 9], _33565254)
T Call: addToList(11, [7, 8, 9, 10], _33565254)
T Exit: addToList(11, [7, 8, 9, 10], [7, 8, 9, 10])
T Exit: addToList(10, [7, 8, 9], [7, 8, 9, 10])
T Exit: addToList(9, [7, 8], [7, 8, 9, 10])
T Exit: addToList(8, [7], [7, 8, 9, 10])
T Exit: addToList(7, [], [7, 8, 9, 10])
X = [7, 8, 9, 10] 

这是我的解决方案:

printSeries(_,[],0):-!.
printSeries(S,[S|T],C):-
S1 is S+1,
C1 is C-1,
printSeries(S1,T,C1).
?- printSeries(7,L,5).
L = [7, 8, 9, 10, 11]

谓词可用于使用起始编号打印任何系列,以及要递增的次数。一个非常简单的方法是使用计数器。第一个谓词是说,无论起始编号如何,无论列表中有什么,如果计数器达到 0,程序都应该削减(意味着停止)。第二个谓词我们有起始编号,以及我们告诉它的列表,您必须以起始编号开始列表,最后是计数器。接下来,我们将起始数字递增 1。将计数器减少 1。然后通过为谓词提供新值来重做所有内容。

?-printSeries(1,L,10).
L = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

最新更新