5

例如,我必须创建 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,[]).
4

4 回答 4

11

如果要创建从 1 到 N 的连续数字列表,可以使用内置谓词findall/3between/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].
于 2012-04-18T12:46:51.970 回答
2

您的代码存在三个问题。第一个问题是您将 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).
于 2012-04-18T05:55:52.887 回答
0

或者,如果您不想使用任何内置功能(像我一样,当我尝试将此作为练习然后遇到此问题时),您可以使用此(有效但无效)解决方案:

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 仅适用于正整数。

于 2018-01-02T10:45:15.703 回答
0

另一种类似于 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).

这也仅适用于正整数。

于 2018-04-19T15:32:10.310 回答