Prolog如何创建一个列表?

6

我需要创建一个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个回答

13

如果你想创建一个从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].

@mat:你说得对,我更新了答案以展示更好的替代方案。 - gusbro

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).

1
你确实有一种神奇的能力,可以发现由于隐式使用模式而引起的问题!我已经在第二个子句中添加了一个测试来避免这个问题。感谢你指出了这个问题。 - twinterer
你现在修复do_list(-1,L)。顺便问一下,哪些系统不需要这个! - false

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).

这仅适用于正整数。


请将以下与编程相���的内容从英语翻译成中文。仅返回已翻译的文本:请使用问题上的编辑链接添加其他信息。Post Answer按钮仅用于完整回答问题。 - Vishnu gondlekar

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).

注:仅适用于正整数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接