第二节 模块与函数(上)

模块

  模块是erlang的基本代码单元.模块保存在扩展名为.erl的文件里,而且必须先编译才能运行模块里面的代码.编译后的模块以.beam作为扩展名.

  我们创建一个geometry.erl的文件

1 -module (geometry).
2 -export ([area/1]).
3 
4 area({rectangle,Width,Height})    ->    Width * Height;
5 area({square, Side})    ->    Side * Side.

  然后在shell中编译这个模块,并且运行它.

  1> c(geometry).
  {ok,geometry}
  2> geometry:area({rectangle, 10, 5}).
  50
  3> geometry:area({square,4}).
  16

  第一行c(文件名)的作用是编译文件里面的代码,运行成功会返回{ok,xxxxxx}这样的结果.同时生成一个.beam的目标代码模块.

  第二行我们通过文件名:方法(参数)的方式来调用模块中的函数.(请注意,需要给函数名附上模块名,这样才能准确标明想调用的是哪个函数).

  下一步,我们试着在模块中添加一些简单的测试模块.把之前那个模块命名为geometry_test.erl

 1 -module (geometry_test).
 2 -export ([test/0,area/1]).
 3 
 4 test()    ->
 5     12 = area({rectangle, 3, 4}),
 6     144 = area({square, 12}),
 7     tests_worked.
 8 
 9 area({rectangle,Width,Height})    ->    Width * Height;
10 area({square, Side})    ->    Side * Side.

  然后我们在shell中编译模块并且运行如果得到test_worked这样的字样就表示测试通过.

  1> c(geometry_test).
  {ok,geometry_test}
  2> geometry_test:text().
  ** exception error: undefined function geometry_test:text/0
  3> geometry_test:test().
  tests_worked

  如果在shell中输入错了函数名就会有错误提示.

  我们给之前的函数扩展一下增加一个area({circle, Radius})  ->  3.14159 * Radius * Radius. 要添加的子句,顺序无关紧要.无论子句如何排列,程序都是一个意思,因为子句里面的各个模式是互斥的.这就让我们编写扩展程序简单了很多.

  最后再看一下我们这个模块,我们会发现有逗号(,)分号(;)句号(.)这样的符号.

  逗号(,)分隔函数调用,数据构造和模式中的参数.

  分号(;)分隔子句.

  句号(.)分隔函数整体.

fun:基本的抽象单元

  erlang是一种函数式的编程语言.此外,函数式编程语言还表示函数可以被用作其他函数的的参数,也可以返回函数.操作其他函数的函数被称为高阶函数,而在erlang中用于代表函数的数据类型被称为fun.

  1.对列表里面的每一个元素执行相同的操作.

  2.创建自己的控制抽象.(erlang中没有for循环)

  3.实现可重入解析代码,解析组合器,或惰性求值器等事物.

  1> Double = fun(X) -> 2*X end.
  #Fun<erl_eval.6.54118792>
  2> Double(2).
  4

  上面就是在shell中定义一个fun的方法.

  下面我们看看定义2个参数是什么样的.

  3> Hypot = fun(X, Y)    ->      math:sqrt(X*X + Y*Y) end.
  #Fun<erl_eval.12.54118792>
  4> Hypot(3,4).
  5.0

  接下来我们以fun作为参数.标准库中lists模块导出了一些以fun作为参数的函数.他们之中最有用的就是lists:map(F,L).这个函数返回的是一个列表,它通过给列表L里的各个元素应用fun F生成.

  5> L = [1,2,3,4].
  [1,2,3,4]
  6> lists:map(fun(X) -> 2*X end, L).
  [2,4,6,8]

  另外一个有用的函数是lists:filter(P, L),它返回一个新的列表,内含L中所有符合条件的元素(条件是对元素E而言P(E)为true).

  Even = fun(X) -> (X rem 2) =:= 0 end.

  定义一个函数Even(X),如果X是偶数就返回true. rem会计算出除以2后的余数,=:=用来测试是否相等.

  然后我们用map和filter为参数.

  10> lists:map(Even, [1,2,3,4,5,6,8]).
  [false,true,false,true,false,true,true]
  11> lists:filter(Even, [1,2,3,4,5,6,8]).
  [2,4,6,8]

  函数不仅可以使用fun作为参数,还能返回fun.

  12> Fruit = [apple,pear,orange].
  [apple,pear,orange]
  13> MakeTest = fun(L) -> (fun(X) -> lists:member(X, L) end) end.
  #Fun<erl_eval.6.54118792>
  14> IsFruit = MakeTest(Fruit).
  #Fun<erl_eval.6.54118792>
  15> IsFruit(pear).
  true
  16> IsFruit(apple).
  true
  17> IsFruit(dog).
  false

  记住括号里面的东西就是返回值.

  下面我们来实现一个自定义的控制抽象,不过到目前为止erlang中我们还没有看见if语句,switch语句,for语句或者while语句,然后这一切都是用模式匹配和高阶函数编写的.我们自己实现一个for结构模块.

1 -module (lib_misc).
2 -export ([for/3]).
3 
4 for(Max, Max, F)    ->    [F(Max)];
5 for(I, Max, F)        ->    [F(I) | for(I+1, Max, F)].

  然后在shell上执行这个模块

  1> lib_misc:for(1,10,fun(I) -> I end).
  [1,2,3,4,5,6,7,8,9,10]
  2> lib_misc:for(1,10,fun(I) -> I*I end).
  [1,4,9,16,25,36,49,64,81,100]

转载于:https://www.cnblogs.com/malkin/p/4907327.html

猜你喜欢

转载自blog.csdn.net/weixin_34352005/article/details/94607727