顺序编程

条件评估

有以下三种形式:

  • 函数模式匹配

    Example:

      area2 ({circle,R}) ->
          math:pi()*R*R;
    
      area2 ({square,Side}) ->
          Side * Side;
    
      area2 (Other) ->
          {error,unknown_shape,Other}.
    
  • case 结构

    表现形式:

      case conditional-expression of
      Pattern1 -> expression1, expression2, .. ;,
      Pattern2 -> expression1, expression2, .. ;
      ... ;
      Patternn -> expression1, expression2, ..
      end
    

    Example:

      area (Shape) ->
          case Shape of 
              {circle,R} -> math:pi()*R*R;
              {square,Side} -> Side * Side;
              Other -> {error,unknown_shape,Other}
          end.
    

    Erlang不推荐防御性编程,这样屏蔽错误,不便于查找问题

  • if

    Example:

      area_if(Shape) ->
          {Type, R} = Shape,
          if 
              Type == circle -> 3.14*R*R;
              Type == square -> R*R
          end.
    

保护元 guard

保护元是额外的限制条件,由 when 和保护元表达式组成。

保护元表达式可使用如下结构组成:

  • 约束变量
  • 常量的数据值,包括数字、基元、元组和列表等
  • 类型测试语句,比如is_boolean等
  • 比较运算符 == 、< 等
  • 算数运算符
  • 布尔表达式
  • 保护元内置函数 (不允许使用用户自定义函数,避免边界效应)

保护元的逻辑组合:

  • (,)分隔,等同于 and ,所有表达式都是true,结果为true。
  • (;)分隔,等同于 or , 一个表达式或者(,)组成的表达式语句为true,结果为true。

example:

my_add2(x,y) when not(x>y), is_atom(x) ; not(is_atom(y)), x =/=3.4 ->
    x+y.

推荐(,)和(;)不要混用,容易造成混淆,产生逻辑错误

内置函数

Erlang 社区中内置函数简写 BIF。 通常是C编写的,集成与VM中。erlang模块列出了标准和非标准的内置函数。(某些也在其他模块,比如ets和lists)

元编程

一个函数在运行时才确定调用哪些函数的特性叫做元编程。我们可以通过apply/3函数来实现。

% apply(Module, Function, Arguments)

M = erlang.
F = now.
apply(M,F,[]).

输入和输出

% 从标准输入读取一行
io:get_line("line>").

% 从标准输入读取指定数量的字符
io:get_chars("chars>",2).

% 从标准输入读取项元
io:read(">").
% >atom.
% {ok,atom}

% 输出项元
io:write/1

% 格式化输出
io:format/2

格式化控制序列:

控制序列 描述
~c 输出一个字符的ASCII码
~f 输出一个有6个小数位的浮点数
~e 输出一个以科学计数法表示的总共6位的浮点数
~w 以标准语法输出任何项元
~p 输出数据就如~w,但在“pretty printing”模式下,在适当地方换行和缩进,在可能的情况下把列表作为字符串输出
~P 输出数据就如~w,~p,但限制结构深度为3.在数据列表中它有额外的一个参数来指明打印项元的最大深度
~B 以10为基数输出一个整数

递归

% 递归
sum([]) -> 0;
sum([Head | Tail]) -> Head + sum(Tail).

% 尾递归   (函数调用发生在函数体的最后一个表达式)
sum_acc([],Sum) -> Sum;
sum_acc([Head | Tail],Sum) -> sum_acc(Tail, Head + Sum).
sum(List) -> sum_acc(List,0).

一般函数语言推荐尾递归,因为尾递归更节约内存,更效率。Erlang早期也是如此,但后来Erlang做过优化,已不能确定尾递归是否更有效率,除非在具体场景进行相应的性能测试。