【新・言語進化論】次にくる!新登場言語
第4回:並列処理が可能な関数型言語「Erlang」
著者: オープンソース・ジャパン 須藤 克彦
公開日:2007/11/26(月)
Erlangのデータ型で特徴的な「リスト」
続いて、Erlangが扱うデータ型の中で特徴的なものを紹介する。
リスト4の上半分「タプル」と呼ばれるものだ。タプルは「もの」をまとめて扱うために使用し、順序も大切な要素として認識される。これに対して下半分は「リスト」と呼ばれている。リストはタプルと同様の働きをするのだが、より重要な働きを備えている。
リスト5のプログラムでは、「total」というモジュールの中に「sum()」という関数を定義している。sum()は引数としてリストが与えられ、リスト中にあらわれる要素をすべて足し算するというものだ。ただし、sum()は引数として2種類を取り得るため、同時に2つの定義を持つ。また「->」によって関数を定義する。
この中で気になるのは「sum([H|T])」の存在だろう。この点については後述するので、まずはコンパイルを行おう。コンパイルの実行とその結果がリスト6だ。「c(モジュール名)」がコンパイルすることを指示している。エラーがなければokが表示される。
リスト4:Erlangが扱う「タプル」と「リスト」
1> T = { 1, 2, 3, 4, 5 }.
{1,2,3,4,5}
2> L = [ 1, 2, 3, 4, 5 ].
[1,2,3,4,5]
リスト5:サンプルプログラム
-module(total).
-export([sum/1]).
sum([H|T]) -> H + sum(T);
sum([]) -> 0.
リスト6:サンプルのコンパイル結果
3> c(total).
{ok,total}
リスト7:totalモジュールの中のsum()を呼び出し
4> total:sum(L).
15
リスト8:「H|T」という引数をリストを受け取り
H <- 1
T <- [2,3,4,5]
続いてリスト4のLを引数としてtotalモジュールの中のsum()を呼び出してみたものが、リスト7だ。
sum()の定義で「sum([H|T]) -> H + sum(T);」という行があったことを思い出してほしい。sum()にはリストが渡されるのだが、行の前半では[H|T]という引数でリストを受け取っている。つまりここでは、リストを「H」と「T」に分解され、リスト8のように代入されているということになるのだ。
このとき、リストの先頭の要素を「head」、残りのリストを「tail」と呼ぶ。ここでは「Hには1そのものが代入され、Tには残りがリストとして代入される」という点がポイントとなる。
さらにTを引数として、再起的に自分自身を呼び出している。なおLISPの知識のあるユーザであれば、headとtailはそれぞれLISPのcarとcdrに相当することに気づくだろう。
Erlangの関数は、名前が同じでも引数が異なれば複数個を定義することができる。sum()の場合、空のリストが渡ってくれば「sub([])」が呼び出され、空でないリストが渡ってくれば「sum([H|T])」が呼び出された上でHとTに分解処理されることになる。
これはオブジェクト指向言語での「オーバーロード」と似ているのだが、すこし違った関数定義の方法だといえるだろう。 次のページ