0

我正在尝试创建一个列表并将其打印出来,从 N 倒数到 1。这是我的尝试:

%% Create a list counting down from N to 1 %%
-module(list).
-export([create_list/1]).

create_list(N) when length(N)<hd(N) ->
 lists:append([N],lists:last([N])-1),
 create_list(lists:last([N])-1); 
create_list(N) ->
 N.

这在 N 为 1 时有效,否则我会收到此错误:

172> list:create_list([2]).
** exception error: an error occurred when evaluating an arithmetic expression
     in function  list:create_list/1 (list.erl, line 6)

任何帮助,将不胜感激。

4

3 回答 3

4

在构建列表时,您通常应该避免使用appendor ++,这是同一回事。它们都将元素添加到列表的末尾,这需要每次都制作列表的副本。有时它很实用,但在列表的前面工作总是更快。

有点不清楚您想要列表的顺序,所以这里有两种选择:

create_up(N) when N>=1 -> create_up(1, N).     %Create the list 

create_up(N, N) -> [N];
create_up(I, N) ->
    [I|create_up(I+1, N)].

create_down(N) when N>1 ->                     %Add guard test for safety
    [N|create_down(N-1)];
create_down(1) -> [1].

这些都不是尾递归的。虽然尾递归很好,但它并不总是像您想象的那样提供,尤其是当您需要调用 areverse以按正确顺序获取列表时。有关更多信息,请参阅Erlang 神话

于 2012-12-14T15:56:53.940 回答
3

错误是lists:last([N])-1。由于 N 是一个数组作为您的输入,lists:last([N])因此将返回 N 本身。不是您期望的数字。如果您在编译代码时看到警告,还有另一个错误:lists:append不会将元素附加到 N 本身,而是在返回值中。在函数式编程中,变量的值不能改变。

这是我的实现:

create_list(N) ->
    create_list_iter(N, []).

create_list_iter(N, Acc) ->
    case N > 0 of
        true -> NewAcc = lists:append(Acc, [N]),
                create_list_iter(N-1, NewAcc);
        false -> Acc
    end.
于 2012-12-14T11:24:34.167 回答
3

如果我正确理解您的问题,这就是您需要的

create_list(N) when N > 0 ->
        create_list(N, []).

create_list(1, Acc) ->
        lists:reverse([1 | Acc]);
create_list(N, Acc) ->
        create_list(N - 1, [N | Acc]).

如果您使用列表,我建议您使用尾递归列表构造语法

此外,为了简化您的代码 - 尝试在函数声明中使用模式匹配,而不是 case 表达式

PS 另一个,也许,最简单的解决方案是:

create_list(N) when N > 0 ->
        lists:reverse(lists:seq(1,N)).
于 2012-12-14T11:32:35.097 回答