今天在看erlang并发编程一书,收益良多,看了第一遍的erlang程序设计,大概也就是泛泛的看了一遍,现在看第二遍,发现收获到更多的东西。把今天看到的erlang并发编程一书中的精华整理一下。
尽管一个典型的程序往往会使用很多不同的函数来操作列表,但大多数列表处理函数都是由少数几种模式演变而来。大部分列表处理函数无非就是在干着这些事情:
1: 在一个列表中寻找一个元素,并在找到时做些事情。
2: 对输入列表的每个元素做些事情并构造一个与其结构相同的输出列表。
3: 在遇到列表中的第n个元素时做些事情。
4: 对列表进行扫描,并构造一个或一组与原列表相关的新列表。
这四句话总结的很好,对于编程,无非就是对程序传入原始数据,然后由程序进行处理最终返回你想得到的最终数据。所以上面erlang的列表处理函数也是遵循这一道路,只不过erlang相比其他语言,显得更加的灵活,更需要动脑筋。
1):搜索列表元素
search(X, [X|T]) ->
... do something ...
...;
search(X, [_|T]) ->
search(X, T);
search(X, []) ->
... didn't find it ...
第一种情况匹配的是找到了我们所感兴趣的项的情形。第二种情况在列表的头部不是我们所感兴趣的项时匹配,这时将接着处理列表的尾部。最后一种情况匹配的是列表元素耗尽的情形。
2):构建同构列表
isomorphic([X|T]) ->
[something(X)|isomorphic(T)];
isomorphic([]) ->
[].
在erlang的世界里,处处是递归,相信你也体会的到了,这里无非就是把列表的每个元素取出来,然后再对元素进行处理,然后又生成新的列表。
比如我们想写一个将给定列表中的所有元素翻倍的函数:
double([H|T]) ->
[2 * H | double(T)];
double([]) ->
[].
> lists1:double([1,7,3,9,12]).
[2,14,6,18,24]
事实上这种手法只能作用于列表的最上层,因此如果我们想遍历列表的所有层次,我们就得将函数定义修改如下:
double([H|T]) when integer(H)->
[2 * H | double(T)];
double([H|T]) when list(H) ->
[double(H) | double(T)];
double([]) ->
[].
后一个版本就可以成功遍历深层的嵌套列表了:
> lists1:double([1,2,[3,4],[5,[6,12],3]]).
[2,4,[6,8],[10,[12,24],6]]
3):计数
不知大家有没有考虑在erlang语言中如何实现for循环的功能,这其实就是要用到erlang的技术功能。
count(Terminal, L) ->
... do something ...;
count(N, [_|L]) ->
count(N-1, L).
则返回列表中第n个元素(假设其存在)的函数可以写成:
nth(1, [H|T]) ->
H;
nth(N, [_|T]) ->
nth(N - 1, T).
这种递减至一个终止条件的计数方式往往要由于递增计数。为了说明这一点,考虑同样是返回第n个元素但是采用递增计数的函数nth1:
nth1(N, L) ->
nth1(1, N, L).
nth1(Max, Max, [H|_]) ->
H;
nth1(N, Max, [_|T]) ->
nth1(N+1, Max, T).
是不是顿时感觉到递归的牛B之处了吧。以前在学数据结构时,我就想过递归是很多算法的母亲,比如搜索,动态规划,树,图等等。
4):收集列表元素
现在我们希望对一个列表中的元素做些动作,生成一个或一组新的列表。对应的模式如下:
collect(L) ->
collect(L, []).
collect([H|T], Accumulator) ->
case pred(H) of
true ->
collect(T, [dosomething(H)|Accumulator]);
false ->
collect(T, Accumulator)
end;
collect([], Accumulator) ->
Accumulator.
在这里我们引入了一个多出一个参数的辅助函数,多出的这个参数用于存储最终要被返回给调用方的列表。
借助这样一种模式,举个例子,我们可以写这样的一个函数:计算输入列表的所有偶元素的平方并删除所有奇元素:
funny(L) ->
funny(L, []).
funny([H|T], Accumulator) ->
case even(H) of
true -> funny(T, [H*H|Accumulator]);
false -> funny(T, Accumulator)
end;
funny([], Accumulator) ->
Accumulator.
于是有:
> lists:funny([1,2,3,4,5,6])
[36,16,4]
刚接触erlang,我感觉自己的思维方式发生了蛮大的变化,发现写erlang很爽
出自:http://svn.liancheng.info/cpie-cn/trunk/.build/html/part-i/chapter-3.html#id10