erlang的lists模块源码解析

本文包括了erlang文档中所有的lists函数,每个函数可能包括如下几部分内容:

  1. 源码 (注:对于sort,merge等与排序有关的函数代码并不完整)
  2. 作用 (对函数作用做简单说明)
  3. 参数限制 (对函数参数或返回值进行说明)
  4. 代码解析 (个人对代码的一些解读)
  5. 疑惑 (对源码的一些疑惑)
  6. 思考 (对源码的一些思考)


lists:all/2

源码:

-spec all(Pred, List) -> boolean() when
   Pred :: fun((Elem :: T) -> boolean()),
   List :: [T],
   T :: term().

all(Pred, [Hd|Tail]) ->
  case Pred(Hd) of
	true -> all(Pred, Tail);
	false -> false
  end

作用:

  • 传入一个函数Pred和列表List,对列表中每个元素执行函数Pred,如果所有都返回true,则怎个函数返回true,否则有一个返回false,就返回false。

参数限制:

  • 函数参数是有且仅有一个任意erlang数据结构。
    返回值必须是boolean()类型。

lists:any/2

源码:

-spec any(Pred, List) -> boolean() when
   Pred :: fun((Elem :: T) -> boolean()),
   List :: [T],
   T :: term().
   
any(Pred, [Hd|Tail]) ->
  case Pred(Hd) of
	true -> true;
	false -> any(Pred, Tail)
  end;
any(Pred, []) when is_function(Pred, 1) -> false.

作用:

  • 和lists:all/2 的不同可以从代码看出,lists:any/2 是只要有一个为true,那么函数就返回true,否则返回false。

参数限制(和lists:all/2 的类型规范相同):

  • 函数参数是有且仅有一个任意erlang数据结构。
  • 返回值必须是boolean()类型。

lists:append/1

源码:

-spec append(ListOfLists) -> List1 when
      ListOfLists :: [List],
      List :: [T],
      List1 :: [T],
      T :: term().

append([E]) -> E;  % 这句的作用?为什么在第一行?
append([H|T]) -> H ++ append(T);
append([]) -> [].

作用:

  • 将ListOfList 整合为一个列表,也就是如果是类似: [ [1,2],[2,4,5]] 返回为 [ 1,2,2,4,5]。

参数限制:

  • ListOfLists是一个列表,列表的第二级必须是列表,第三级可以是任意erlang数据类型。

lists:subtract/2

源码:

-spec subtract(List1, List2) -> List3 when
      List1 :: [T],
      List2 :: [T],
      List3 :: [T],
      T :: term().

subtract(L1, L2) -> L1 -- L2.

作用:

  • 去除掉List1中所有的List2元素。这里使用的-- ,则需要注意,如果List1中有3个a元素,List2中有2个a元素,那么结果只是去除List1中的2个a元素。(可以去搜索–符号的定义。)

参数限制:

  • 参数是一个列表,列表的每个元素可以是任意erlang数据类型。

lists:reverse/2

源码:

-spec reverse(List1, Tail) -> List2 when
      List1 :: [T],
      Tail :: term(),
      List2 :: [T],

      T :: term().

reverse(_, _) ->
    erlang:nif_error(undef).

疑惑:

  • 这个函数的 erlang:nif_error(undef).没有看懂。reverse/1 第四个子句会调用这个函数是什么目的?

lists:reverse/1

源码:

-spec reverse(List1) -> List2 when
      List1 :: [T],
      List2 :: [T],
      T :: term().

reverse([] = L) ->
    L;
reverse([_] = L) ->
    L;
reverse([A, B]) ->
    [B, A];
reverse([A, B | L]) ->
    lists:reverse(L, [B, A]).

作用:

  • 反转List1中元素。

代码解析:

  • 前三个子句针对列表只有0个或1个或2个的情况。如果列表元素超过3个,则匹配第三个子句。

lists:nth/2

源码:

-spec nth(N, List) -> Elem when
      N :: pos_integer(),
      List :: [T,...],
      Elem :: T,
      T :: term().

nth(1, [H|_]) -> H;
nth(N, [_|T]) when N > 1 ->
    nth(N - 1, T).

作用:

  • 获得列表中的第N个元素。

代码解析:

  • 如果N为1,那么直接返回列表第1个元素;如果N大于1,那么就一直匹配第2个子句,直到N=1,且列表为排除前N-1个元素的列表,这时第1个元素就是原列表的第N个元素。

lists:nthtail/2

源码:

-spec nthtail(N, List) -> Tail when
      N :: non_neg_integer(),
      List :: [T,...],
      Tail :: [T],
      T :: term().

nthtail(1, [_|T]) -> T;
nthtail(N, [_|T]) when N > 1 ->
    nthtail(N - 1, T);
nthtail(0, L) when is_list(L) -> L.

作用:

  • 返回列表中第N+1 到结尾的列表。

代码解析:

  • 第1-2个子句作用和nth/1函数相同,直到匹配到N为1,列表为N到结尾。最后一个是匹配当N为0时,判断L是否为列表。

思考:

  • 如果第3个子句没有 when is_list(L) ,那么是否可以写成:
    nthtail(0, L) -> L;
    nthtail(N, [_|T]) when N >0 ->
    nthtail(N - 1, T);
    问题在于,when is_list(L) 意义何在?

lists:prefix/2

源码:

-spec prefix(List1, List2) -> boolean() when
      List1 :: [T],
      List2 :: [T],
      T :: term().

prefix([X|PreTail], [X|Tail]) ->
    prefix(PreTail, Tail);
prefix([], List) when is_list(List) -> true;
prefix([_|_], List) when is_list(List) -> false.

作用:

  • 判断List1是否是List2的前缀,是返回true,否则返回false。

代码解析:

  • 第1个子句明显是做等值匹配,第2-3个子句判断,如果匹配了所有相等元素之后List2是否为空,如果是则返回true,否则返回false。

lists:suffix/2

源码:

-spec suffix(List1, List2) -> boolean() when
      List1 :: [T],
      List2 :: [T],
      T :: term().

suffix(Suffix, List) ->
    Delta = length(List) - length(Suffix),
    Delta >= 0 andalso nthtail(Delta, List) =:= Suffix.

作用:

  • 判断List1是否是List2的后缀,是返回true,否则返回false。

代码解析:

  • 首先判断List2长度是否大于List1,如果大于则继续判断,nthtail/2函数,获得List2的最后Delta个元素,与Suffix进行完全等值匹配。如果两个判断都为true,返回true,否则返回false。

思考:

  • 为什么前缀判断不这样先判断长度,然后直接截取与带判断相同的前缀列表,再做完全等值判断呢?
    这可能是因为,要截取出前缀同样需要函数递归寻找,而suffix,调用的nthtail也是做了递归寻找工作,因此不需要再自己写代码了,直接使用就可。

lists:droplast/1

源码:

-spec droplast(List) -> InitList when
      List :: [T, ...],
      InitList :: [T],
      T :: term().

droplast([_T])  -> [];
droplast([H|T]) -> [H|droplast(T)].

作用:

  • 删除列表最后一个元素。

参数限制:

  • 从类型规范中可以看出List必须有一个元素,也就是不能为空,否则报错。

代码解析:

  • 第1个子句匹配时已经是最后一个元素,直接忽略,返回空列表;第2个子句做递归,直到最后一个元素。

lists:last/1

源码:

-spec last(List) -> Last when
      List :: [T,...],
      Last :: T,
      T :: term().

last([E|Es]) -> last(E, Es).

last(_, [E|Es]) -> last(E, Es);
last(E, []) -> E.

作用:

  • 返回最后一个元素。

参数限制:

  • 列表不能为空

代码解析:

  • 主题为last/2 函数,它第1个子句递归调用,直到尾列表为空,则返回。

lists:seq/2

源码:

-spec seq(From, To) -> Seq when
      From :: integer(),
      To :: integer(),
      Seq :: [integer()].

seq(First, Last)
    when is_integer(First), is_integer(Last), First-1 =< Last -> 
    seq_loop(Last-First+1, Last, []).

seq_loop(N, X, L) when N >= 4 ->
     seq_loop(N-4, X-4, [X-3,X-2,X-1,X|L]);
seq_loop(N, X, L) when N >= 2 ->
     seq_loop(N-2, X-2, [X-1,X|L]);
seq_loop(1, X, L) ->
     [X|L];
seq_loop(0, _, L) ->
     L.

作用:

  • 返回First到Last的列表。当First=Last返回First值,如果First=Last +1返回空列表。

参数限制:

  • First <= Last+1。

代码解析:

  • 函数分两部分,主体为seq_loop/3,利用第三个参数叠加值并返回。
    第一参数是列表的大小,也就是要创建多少个元素。函数从最后一个元素开始创建,这样最后的列表顺序才正确。
    函数妙的地方在于seq_loop/3的第1-2个子句,它们会对列表匹配做4个或2个的跳跃。利用[ X-3,X-2,X-1,X|L] 来直接创建4个或2个待入列元素。

lists:seq/3

源码:

-spec seq(From, To, Incr) -> Seq when
      From :: integer(),
      To :: integer(),
      Incr :: integer(),
      Seq :: [integer()].

seq(First, Last, Inc) 
    when is_integer(First), is_integer(Last), is_integer(Inc) -> 
    if
        Inc > 0, First - Inc =< Last;
        Inc < 0, First - Inc >= Last ->
            N = (Last - First + Inc) div Inc, % 计算有多少个数
            seq_loop(N, Inc*(N-1)+First, Inc, []);
        Inc =:= 0, First =:= Last ->
            seq_loop(1, First, Inc, [])
    end.

seq_loop(N, X, D, L) when N >= 4 ->
     Y = X-D, Z = Y-D, W = Z-D,
     seq_loop(N-4, W-D, D, [W,Z,Y,X|L]);
seq_loop(N, X, D, L) when N >= 2 ->
     Y = X-D,
     seq_loop(N-2, Y-D, D, [Y,X|L]);
seq_loop(1, X, _, L) ->
     [X|L];
seq_loop(0, _, _, L) ->
     L.

作用:

  • 返回First到Last范围内,以Incr为等差值的列表。

代码解析:

  • seq/3的代码和seq/2差不多,不同之处在于多了一个等差值D,可以注意到seq_loop的第一个子句没有使用如Y=X-3D,Z=X-2D之类的代码是为了提高效率,因为加法比乘法快。

lists:merge/1

源码:

-spec merge(ListOfLists) -> List1 when
   ListOfLists :: [List],
   List :: [T],
   List1 :: [T],
   T :: term().

merge(L) ->
  mergel(L, []).

作用:

  • 将ListOfLists中的列表合并,如果想要合并之后有序,那么每个子列表需要自行先排序。否则无法保证返回列表有序。

参数限制:

  • ListOfLists的子元素必须是列表。

lists:merge/2

源码:

-spec merge(List1, List2) -> List3 when
   List1 :: [X],
   List2 :: [Y],
   List3 :: [(X | Y)],
   X :: term(<
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值