例如,我必须创建 n 个元素的列表,
do_list(5,L1).
应该返回,
L1=[1,2,3,4,5].
这就是我所拥有的,但它不起作用。
do_list(X,L1):- X1 is X-1, do_list(X1,[X1|L1]).
do_list(0,[]).
例如,我必须创建 n 个元素的列表,
do_list(5,L1).
应该返回,
L1=[1,2,3,4,5].
这就是我所拥有的,但它不起作用。
do_list(X,L1):- X1 is X-1, do_list(X1,[X1|L1]).
do_list(0,[]).
如果要创建从 1 到 N 的连续数字列表,可以使用内置谓词findall/3
,between/3
这样:
do_list(N, L):-
findall(Num, between(1, N, Num), L).
?- do_list(5,L).
L = [1, 2, 3, 4, 5].
SWI 还有另一个内置函数可以做到这一点numlist/3
:
?- numlist(1,5,L).
L = [1, 2, 3, 4, 5].
您的代码存在三个问题。第一个问题是您将 X1 添加到子句主体中的列表中,但您从未将新列表传递回子句的头部。即,L1 是一个累加器变量,但您需要绑定到最终列表的第三个参数。
第二个是第二个子句仅在输入列表为空时匹配。永远不会出现这种情况,因为您在do_list/2
递归调用之前将 X1 添加到列表中。即,您没有递归锚,目标?- do_list(5,L)
永远不会返回。
第三个问题是您将 X1 而不是 X 添加到列表中。您将跳过最大的数字。
这是它应该如何工作的:
do_list(N, L) :- do_list1(N, [], L).
do_list1(0, L, L) :- !.
do_list1(N, R, L) :- N > 0, N1 is N-1, do_list1(N1, [N|R], L).
或者,如果您不想使用任何内置功能(像我一样,当我尝试将此作为练习然后遇到此问题时),您可以使用此(有效但无效)解决方案:
connect([],X,X).
connect([H|T],C,[H|T2]) :- connect(T,C,T2).
revert([],[]).
revert([H|T],R) :- revert(T,Trev), connect(Trev,[H],R)
do_revlist(0,[]).
do_revlist(X,[X|L]) :- X1 is X-1, do_revlist(X1,L).
do_list(X,L2) :- do_revlist(X,L), revert(L,L2).
PS 仅适用于正整数。
另一种类似于 twinterer 的解决方案,但没有切割或预定义谓词,采用累加器。
do_List(Max,L) :- do_ListAcc(1,Max,L). % call Accumulator
do_ListAcc(N,N,[N]). % N=:=N ends recursion
do_ListAcc(Min,Max,[Min|Succs]) :-
Next is Min + 1,
do_ListAcc(Next,Max,Succs).
这也仅适用于正整数。