摘要: 翻译太菜希望大牛指正。以后会逐渐加入自己写的注释和疑问,有些地方自己也不太了解,知道或者感兴趣的同学可以指出来,一起讨论一下。
=====================================================================================================
List handling 1 Creating a list 创建一个列表Lists can only be built starting from the end and attaching list elements at the beginning. If you use the ++ operator like this
列表只能从尾端开始创建,从头部加入元素。如果你像这样使用++操作符
List1 ++ List2
you will create a new list which is copy of the elements in List1, followed by List2. Looking at how lists:append/1 or ++would be implemented in plain Erlang, it can be seen clearly that the first list is copied:
你将创建一个新的列表,这个列表是List1的副本加上List2。看看lists:append/1函数或者++操作符在Erlang里面是怎样实现的,可以明了地看到第一个列表被复制了:(%% 取一个输入列表的元素,加到新的列表中 %%)
append([H|T], Tail) -> [H|append(T, Tail)]; append([], Tail) -> Tail.
So the important thing when recursing and building a list is to make sure that you attach the new elements to the beginning of the list, so that you build a list, and not hundreds or thousands of copies of the growing result list.
所以在递归遍历和构造一个列表的时候,香港空间,要确保把新的元素附加到列表的头部,这样就能避免产生成百上千的列表的副本。
Let us first look at how it should not be done:
让我们首先来看看不应该使用的方法:
DO NOT
bad_fib(N) -> bad_fib(N, 0, 1, []). bad_fib(0, _Current, _Next, Fibs) -> Fibs; bad_fib(N, Current, Next, Fibs) -> bad_fib(N - 1, Next, Current + Next, Fibs ++ [Current]).
Here we are not a building a list; in each iteration step we create a new list that is one element longer than the new previous list.
这里我们并不是在创建一个列表;每一次迭代中,我们都产生了一个新的列表,这个新的列表比上次产生的列表还多一个元素。
To avoid copying the result in each iteration, we must build the list in reverse order and reverse the list when we are done:
为了避免在每次迭代中复制最后的结果,我们必须以相反顺序来构造列表,然后在结束的时候反转列表:
DO
tail_recursive_fib(N) -> tail_recursive_fib(N, 0, 1, []). tail_recursive_fib(0, _Current, _Next, Fibs) -> lists:reverse(Fibs); tail_recursive_fib(N, Current, Next, Fibs) -> tail_recursive_fib(N - 1, Next, Current + Next, [Current|Fibs]).
2 List comprehensions 列表解析
Lists comprehensions still have a reputation for being slow. They used to be implemented using funs, which used to be slow.
列表解析仍然被认为是效率慢的。它们以前是使用函数来实现的,而函数过去也是效率慢的。
In recent Erlang/OTP releases (including R12B), a list comprehension
在最近的Erlang/OTP版本中(包括R12B),列表解析
[Expr(E) || E <- List]
is basically translated to a local function
被转换成一个本地函数
'lc^0'([E|Tail], Expr) -> [Expr(E)|'lc^0'(Tail, Expr)]; 'lc^0'([], _Expr) -> [].
In R12B, if the result of the list comprehension will obviously not be used, a list will not be constructed. For instance, in this code
在R12B版本中,如果列表解析的结果明确表示出将不会被使用的,那么列表将不会被构造出来。例如,在下面这段代码中
[io:put_chars(E) || E <- List], ok.
or in this code
或者下面这段代码
. . . case Var of ... -> [io:put_chars(E) || E <- List]; ... -> end, some_function(...), . . .
the value is neither assigned to a variable, nor passed to another function, nor returned, so there is no need to construct a list and the compiler will simplify the code for the list comprehension to
列表里面的元素既不会赋值给一个变量,也不会传给另外一个函数,或者直接返回,所以这种情况下是没有必要构造一个列表的,编译器会简单地把列表解析的代码简化成下面的形式(%% 一是没有了列表结构,二是用了尾递归 %%)
'lc^0'([E|Tail], Expr) -> Expr(E), 'lc^0'(Tail, Expr); 'lc^0'([], _Expr) -> [].
3 Deep and flat lists 深度扁平列表