Erlangの関数は、かなり見た目が他の言語と異なります。
しかし、やっていることはほとんど同じですのでまずは両者を比較してみましょう。
関数は引数を二つ取り、その値を足し合わせて2倍するというものです。
処理を分かりやすくするため、わざと短縮しないで書きます。
Erlang言語
function(X, Y) ->
Z = X + Y,
Z * 2.
C言語
int function(int x, int y){
int z = x + y;
return z * 2;
}
Java言語
public int function(int _x, int _y){
int z = _x + _y;
return z * 2;
}
確かに見た目は違いますけど、形は似ていますよね。
Erlangの関数においては、「 -> 」の前が変数名と引数で、その後ろが処理になっています。
そして、関数の途中の式が「 , 」で終わっていて、最後の式が「 . 」で終わっています。
これがErlangの一番簡単な関数の形です。
直径(Diameter)から半径(Radius)を求めて、面積を計算する関数
circle(Diameter) ->
Radius = Diameter/2,
Radius * Radius * 3.14.
それぞれのパーツを見て行きます。
関数名 circle
アリティ(引数の数) 1
処理
Radius = Diameter/2,
Radius * Radius * 3.14.
返り値(最後の式)
"Radius * Radius * 3.14."の実行結果
それぞれの部分に名前があったほうが分かりやすいので、名前を定義します。
function(parameter) ->
do_something,
do_something.
"->"の左側にあるのは変数名と引数で、ヘッド(クローズヘッド)と呼びます。
また、引数の数をアリティと呼びます。
右側にあるのは一連の式で、ボディ(クローズボディ)と呼びます。
関数の実行は簡単です。
モジュール名:関数名(引数)
という書式で使います。
mymath.erl
-module(mymath).
-export([add/2, multi/2]).
add(X,Y) ->
X + Y.
multi(X,Y) ->
X * Y.
1> mymath:add(3,5).
8
同じモジュール内にあったり、インポート(前節を参照して下さい)されている関数は、 モジュール名を指定しなくても呼び出すことが可能です。
CやJavaにおける関数(メソッド)のオーバロードとは、引数の数(アリティ)が異なったり、 引数の型が違ったら、同じ関数名でも別の関数として扱われるというものです。
Erlangはパターンマッチを使って似たようなことを行いますが、
これはCやJavaの関数のオーバーロードよりも強力です。
書式は、同名同アリティの節(クローズ)を並べていき、
パターンマッチされた節を実行するというものです。
節は関数の一部と言えます。
area(circle,X) ->
X * X * 3.14;
area(square,X) ->
X * X;
area(Other,X) ->
io:format("~p is not supported~n",[Other]),
X.
1> mod:area(circle,5).
78.5000
2> mod:area(rectangle,5).
rectangle is not supported
5
3> mod:area(square,5).
25
関数areaは3つの節から構成されています。アリティは同じですけど、引数の内容が異なっていますね。
関数が呼び出された場合は上の節からパターンマッチされていき、それが当てはまる場合はその節が評価されます。
上の例をよく見てみて、引数として何を渡した時に、どの節が実行されているかということを確認してみて下さい。
節の書式で非常に重要なことがあります。
それは、節の最後の式には「 ; 」と「 . 」の2つがあることです。
良く見てみると、第一節と第二説が「 ; 」で、第三節が「 . 」となっています。
実は最終節が「 . 」を使って、 それ以外は「 ; 」を使うというルールがあります。
これは他の言語ではあまり見られないため、うっかり間違えてしまうことが多いです。
エラーの際はこのあたりを調べてみると解決できることが多いと思います。
気をつけて下さい。
関数がどのように処理されるのか、実際に見て行きましょう。
mod:area(square,5)を呼び出した場合は、
一つ目の節のarea(circle,X)とは第一引数が一致しません。
そして二つ目の節のarea(square,X)と一致して、その節が評価されているのがわかりますね。
パターンマッチングが使われています。
注意するべきなのは節の順番です。
例えば先ほどのプログラムにおいて、三つ目の節を一番上に持ってくるとパターンマッチは常に第一節で成り立ってしまいます。
そういう処理を書くとコンパイルの際に、「これ以降の節は利用されることがありません」と注意されてしまいます。
節はマッチしにくい条件から並べる必要があります。
また、どの節にもマッチしないとエラーとなってしまうことには注意する必要があります。
上の例で、もし
area(Other,X) ->
io:format("~p is not supported~n",[Other]),
X.
がない状態で
mod:area(rectangle,5).
と実行したらエラーになってしまいます。