首页 > Erlang快速入门 > 3.13 Erlang快速入门之高阶函数
2013
11-01

3.13 Erlang快速入门之高阶函数

高阶函数(Funs)
Erlang和其他的函数式编程语言一样,有一些高端的函数,我们下面就来看看这部分的内容:

90> Xf = fun(X) -> X * 2 end.
#Fun<erl_eval.5.123085357>
91> Xf(5).
10    

我们在这里定义了一个函数,其功能是将输入的数值乘以2.于是我们调用Xf(5)得到结果10.两个在日常工作中有用的函数是foreach和map,定义如下:

foreach(Fun, [First|Rest]) ->
    Fun(First),
    foreach(Fun, Rest);
foreach(Fun, []) ->
    ok.
map(Fun, [First|Rest]) -> 
    [Fun(First)|map(Fun,Rest)];
map(Fun, []) -> 
    [].    

这两个函数都在模块lists中。foreach需要一个列表作为输入,然后对每个列表元素应用一次fun函数。而map则创建一个新的列表来保存被fun函数作用过的列表元素。回到shell中,我们使用map和fun对列表中的每个元素都加上3:

92> Add_3 = fun(X) -> X + 3 end.
#Fun<erl_eval.5.123085357>
93> lists:map(Add_3, [1,2,3]).
[4,5,6] 

现在让我们输出城市的温度列表:

95> Print_City = fun({City, {X, Temp}}) -> io:format("~-15w ~w ~w~n",
 [City, X, Temp]) end.
#Fun<erl_eval.5.123085357>
96> lists:foreach(Print_City, [{moscow, {c, -10}}, {cape_town, {f, 70}},
 {stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).
moscow          c -10
cape_town       f 70
stockholm       c -4
paris           f 28
london          f 36
ok    

我们现在定义一个fun函数,来将列表中的华氏度全部转换为摄氏度:

-module(tut13).
-export([convert_list_to_c/1]).
convert_to_c({Name, {f, Temp}}) ->
    {Name, {c, trunc((Temp - 32) * 5 / 9)}};
convert_to_c({Name, {c, Temp}}) ->
    {Name, {c, Temp}}.
convert_list_to_c(List) ->
    lists:map(fun convert_to_c/1, List).  

编译运行:

  
98> tut13:convert_list_to_c([{moscow, {c, -10}}, {cape_town, {f, 70}},
 {stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).
[{moscow,{c,-10}},
 {cape_town,{c,21}},
 {stockholm,{c,-4}},
 {paris,{c,-2}},
 {london,{c,2}}]    

convert_to_c函数的功能和上面相同,只不过我们使用了一个fun:
lists:map(fun convert_to_c/1, List)
但我们使用一个在其他地方定义的函数作为fun时,我们应该明确的知道它的方法名和参数数量(Function/Arity)。所以在map中我们写
lists:map(fun convert_to_c/1,List)。
你可以看到convert_list_to_c变短了,变得更加容易阅读理解了。
标准模块lists同样包含了函数sort(Fun,List),这里的fun带有两个参数。如果第一个参数小于第二个参数则fun应该返回true,否则应该返回false。我们将其添加到convert_list_to_c中:

-module(tut13).
-export([convert_list_to_c/1]).
convert_to_c({Name, {f, Temp}}) ->
    {Name, {c, trunc((Temp - 32) * 5 / 9)}};
convert_to_c({Name, {c, Temp}}) ->
    {Name, {c, Temp}}.
convert_list_to_c(List) ->
    New_list = lists:map(fun convert_to_c/1, List),
    lists:sort(fun({_, {c, Temp1}}, {_, {c, Temp2}}) ->
                       Temp1 < Temp2 end, New_list).    

编译运行:

99> c(tut13).
{ok,tut13}
100> tut13:convert_list_to_c([{moscow, {c, -10}}, {cape_town, {f, 70}},
 {stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).
[{moscow,{c,-10}},
 {stockholm,{c,-4}},
 {paris,{c,-2}},
 {london,{c,2}},
 {cape_town,{c,21}}]   

在sort中我们使用fun:
fun({_, {c, Temp1}}, {_, {c, Temp2}}) -> Temp1 < Temp2 end,
这里我们引入了一个概念——匿名变量“_”(anonymous variable)。这是一种当获取一个值时的缩写的形式,但是我们将忽略这个值。我们可以在任何地方使用这个匿名特性,不仅仅是在fun中。Temp1


3.13 Erlang快速入门之高阶函数》有 7 条评论

  1. itsqe 说:

    没看懂。

  2. exit 说:

    请问作者{Name, {c, trunc((Temp – 32) * 5 / 9)}};这句话里面的trunc是什么意思啊?

  3. AAA 说:

    取整数

  4. exit 说:

    谢谢,我后来看到了。

  5. 追风 说:

    感谢楼主 受教了

  6. 外贸电商 说:

    [犯错] 再来学习一边。。

留下一个回复

你的email不会被公开。