第二节 模块与函数(下)
简单列表处理
上一节我们重点介绍了fun,现在我们继续编写sum和map,来改进我们之前实现的total总和的计算.新建一个mylists.erl
1 -module (mylists). 2 -export ([sum/1]). 3 4 sum([H | T]) -> H + sum(T); 5 sum([]) -> 0.
然后在shell上执行.
1> L = [1,3,10].
[1,3,10]
2> mylists:sum(L).
14
然后我们在原有的lists上增加一个map的方法.
1 -module (mylists). 2 -export ([sum/1,map/2]). 3 4 sum([H | T]) -> H + sum(T); 5 sum([]) -> 0. 6 7 map(_, []) -> []; 8 map(F, [H | T]) -> [F(H) | map(F, T)].
运行结果如下:
1> L = [1,2,3,4,5].
[1,2,3,4,5]
2> mylists:map(fun(X) -> 2*X end, L).
[2,4,6,8,10]
3> mylists:map(fun(X) -> X*X end, L).
[1,4,9,16,25]
现在我们已经了解了sum和map,我们准备用这个来写shop2.erl
1 -module (shop2). 2 -export ([total/1]). 3 -import (lists, [map/2, sum/1]). 4 5 total(L) -> sum(map(fun({What, N}) -> shop:cost(What) * N end, L)).
运行后结果是:
1> L = [1,2,3,4,5].
[1,2,3,4,5]
2> mylists:map(fun(X) -> 2*X end, L).
[2,4,6,8,10]
3> mylists:map(fun(X) -> X*X end, L).
[1,4,9,16,25]
-import和-export的用法:
-import(lists, [map/2,sum/1])声明的意思是map/2函数从lists模块里导入的.
-export([total/1])声明的意思是total/1函数可以在shop2模块之外调用.只有从一个模块里导出的函数才能在该模块之外调用.
列表推导
列表推导是无需使用fun,map或filter就能创建列表的表达式.它让程序变得更短,更容易理解.
以前我们是用lists:map来实现的
1> L = [1,2,3,4,5].
[1,2,3,4,5]
2> lists:map(fun(X) -> 2*X end, L).
[2,4,6,8,10]
现在我们看看用列表推导是怎么实现的:
3> [2*X || X <- L].
[2,4,6,8,10]
[ F(X) || X <- L]标记的意思是"由F(X)组成的列表(X从列表L中提取)"
请注意,||符号右边的X是一个模式,用于匹配列表L里面的各个元素.左侧的2*X则是一个构造器.
最后我们给shop2.erl改成列表推导的方式
total(L) ->
lists:sum([shop:cost(A)*B||{A,B} <- L]).
列表推导最常规的形式是这种表达式:[X || Qualifier1, Qualifier2, ...] X是任意一条表达式,后面的限定符可以是生成器,位串生成器或过滤器.
1.生成器的写法Pattern <- ListExpr,其中的ListExp必须是一个能够得出列表的表达式.
2.位串生成器的写法是BitStringPattern <= BitStringExpr,其中的BitStringExpr必须是一个能够得出位串的表达式.
3.过滤器既可以是判断函数,也可以是布尔表达式. [X || {a, X} <- [{a,1},{b,2},{c,3},{a,4},hello,"WoW"]].执行结果就是[1,4]
内置函数
内置函数简称BIF,是那些作为erlang语言定义一部分的函数.
关卡
关卡是一种结构,可以用它来增加模式匹配的使用.
case和if表达式
case的语法如下:
case Expression of
Pattern1 [when Guard1] -> Expr_seq1;
Pattern2 [when Guard2] -> Expr_seq2;
......
end
erlang还提供了第二种条件表达式if:
if
Guard1 ->
Expr_seq1;
Guard2 ->
Expr_seq2;
...
end