無題の備忘録

IT技術について調べたことや学んだこと、試したこと記録するブログです。Erlang、ネットワーク、 セキュリティ、Linux関係のものが多いです。

Erlang の lists モジュールを一通り試す - その1

最近、Erlang のコードを読んでいて、lists:any という関数が出てきたのだが、知らなかったので調べた。ついでに、他の関数も一通り眺めておく。

公式URL: http://erlang.org/doc/man/lists.html

all/2 関数

all(Pred, List) -> boolean()

Types

Pred = fun((Elem :: T) -> boolean())
List = [T]
T = term()

Pred(Elem) がすべてのElem について true を返す場合はtrueを、それ以外の場合はfalseを返す。Pred は変数で関数がバインドされている。こんとき、第1引数 (Pred) に渡す関数は、boolean() を返す必要がある。

$ erl
...(省略)
> IsAtom = fun(X) -> is_atom(X) end.
#Fun<erl_eval.6.99386804>
> lists:all(IsAtom, [a,b,c,d,e]).
true
> lists:all(IsAtom, [a,b,c,d,e,1]). 
false

上記の例は、IsAtomという変数に、fun(X) -> is_atom(X) end.という無名関数をバインドしている。IsAtomを第1引数に、[a, b, c, d, e]というリストを第2引数に渡すと、リストの1つづつをIsAtomの関数で処理する。IsAtomの関数の実態はis_atom(X)関数で渡されたリストの1つがXに入って、Xがアトムかどうかをチェックする。Xがアトムなら true を返す。1つ目の例は、[a, b, c, d, e] はすべて atom なので、 lists:all関数は true を返す。2つ目の[a,b,c,d,e,1]は1つだけ整数が入っているので、false を返している。

any/2 関数

any(Pred, List) -> boolean()

Types

Pred = fun((Elem :: T) -> boolean())
List = [T]
T = term()

リスト内の少なくとも1つの要素Elemに対して Pred(Elem) がtrueを返す場合、trueを返す。

> IsAtom = fun(X) -> is_atom(X) end.
#Fun<erl_eval.6.99386804>
> lists:any(IsAtom, [a,b,c,d,e]).
true
> lists:any(IsAtom, [a,b,c,1,2]).
true
> lists:any(IsAtom, [1,2,3,4,5]).
false

第1引数は、リストの要素がatomかどうかを判定をする関数である。リスト内に少なくとも1つatomがあれば、trueを返している。すべて、atomでない場合は falseを返す。

append/1 関数

append(ListOfLists) -> List1

Types

ListOfLists = [List]
List = List1 = [T]
T = term()

ListOfListsのすべてのサブリストが追加されたリストを返す。

> List1 = [1,2,3].
[1,2,3]
> List2 = [a,b].
[a,b]
> List3 = [4,5,6].
[4,5,6]
> lists:append([List1, List2, List3]).
[1,2,3,a,b,4,5,6]

複数のリストをまとめて1つのリストにしたいときに使います。

append/2 関数

append(List1, List2) -> List3

Types

List1 = List2 = List3 = [T]
T = term()

List1の要素とList2の要素から構成される新しいリストList3を返す。

> List1 = [1,2,3].
[1,2,3]
> List2 = [a,b].
[a,b]
> lists:append(List1, List2).
[1,2,3,a,b]

2つのリストを1つのリストにする。Erlangの文字列の実体はリストなので、文字列の連結にも使える。

> lists:append("abc", "def").
"abcdef"

concat/1 関数

concat(Things) -> string()

Types

Things = [Thing]
Thing = atom() | integer() | float() | string()

Thingsの要素のテキスト表現を連結します。 Thingsの要素は、原子、整数、浮動小数点数、または文字列のどれか。

> lists:concat([path,'/', to, "/", 1]).
"path/to/1"

atomや数値をそのまま与えても文字列化した上で連結してくれる関数。文字列は文字のコードポイントのリストなので、このような関数が lists モジュールに含まれている。

delete/2

delete(Elem, List1) -> List2

Types

Elem = T
List1 = List2 = [T]
T = term()

Elem の要素がある場合に、List1 から Elem を削除したリストのコピーを返す。

>lists:delete(1, [1,2,3,4,5]).
[2,3,4,5]
> lists:delete({a, "Alice"}, [{a, "Alice"},{b, "Bob"}]).
[{b,"Bob"}]

Elem は term() なので、{a, "Alice"} のようなタプルでも要素と一致すれば、削除される。

droplast/1 関数

droplast(List) -> InitList

Types

List = [T, ...]
InitList = [T]
T = term()

リストの最後の要素を削除する。ただし、リストが空の場合は、function_clause で関数がクラッシュする。

> lists:droplast([a,b,c,d,e]).                          
[a,b,c,d]
> lists:droplast([a]).
[]
> lists:droplast([]).         
** exception error: no function clause matching lists:droplast([]) (lists.erl, line 218)

try catch で囲むと、クラッシュエラーの理由が fanction_clause になっていることがわかる。

18> try lists:droplast([]) catch Type:Reason -> io:format("Type:~p Reason:~p~n",[Type,Reason]) end.
Type:error Reason:function_clause
ok

dropwhile/2 関数

dropwhile(Pred, List1) -> List2

Types

Pred = fun((Elem :: T) -> boolean())
List1 = List2 = [T]
T = term()

Pred(Elem)が true を返す間、List1 から要素 Elem を削除し、残りのリストを返す。

19>  IsAtom = fun(X) -> is_atom(X) end.
#Fun<erl_eval.6.99386804>
20> lists:dropwhile(IsAtom, [a,b,c,d,e]).
[]
21> lists:dropwhile(IsAtom, [a,b,c,1,2]).
[1,2]
22> lists:dropwhile(IsAtom, [a,1,c,2,3]).
[1,c,2,3]
23> lists:dropwhile(IsAtom, [1,2,3,4,5]).
[1,2,3,4,5]

また IsAtom に 引数が atom かどうかをチェックする無名関数をバインドする。上記の例をみるとわかるように、リストの先頭の要素から順番に第1引数に指定した関数のチェックを行い、trueである限り削除する。途中で false になった場合、それ以降のリストのチェックは行われない。

duplicate/2 関数

duplicate(N, Elem) -> List

Types

N = integer() >= 0
Elem = T
List = [T]
T = term()

term() である Elem の N 個のコピーを含むリストを返す。

> lists:duplicate(5, a). 
[a,a,a,a,a]
> lists:duplicate(5, {a, [{a, "Alice"}]}).
[{a,[{a,"Alice"}]},
 {a,[{a,"Alice"}]},
 {a,[{a,"Alice"}]},
 {a,[{a,"Alice"}]},
 {a,[{a,"Alice"}]}]

このとき、Elem は Erlangで表現できるものであれば、どんなものでもコピーする。