Erlang入門

# Erlang入門
Erlangの特徴は並列処理を言語やVMでサポートしている関数型言語です。
また、ErlangはPrologやその後継である並列論理型言語の強い影響を受けていて構文やVMの構造などにその影響が見られます。

## インストール

### Windows
<http://www.erlang.org/downloads>
よりインストーラをダウンロードしてインストールしてください。

### Mac

````
brew install erlang
````
でインストールできます。

### Linux
Debian系なら
````
apt install erlang
````
## 対話環境
### Windows
````
"スタート" -> "全てのプログラム" -> "Erlang OTP " -> "Erlang"
````
### Mac & Linux
ターミナルより
````
$ erl
````
と打ち込むことで対話環境が立ち上がります。
ためしに `1+2+3.`と打ち込んで見ましょう。

````
$ erl
Erlang R16B03 (erts-5.10.4) [source] [64-bit] [async-threads:10] [kernel-poll:false]

Eshell V5.10.4  (abort with ^G)
1>
6
2>
````

`6`と表示されます。これは式`1 + 2 + 3.`が計算された結果です。Erlangでは`;`の代わりに`.`が使われます。

## コンパイル
`erlc`コマンドでコンパイルします。
ErlangはBEAMというVM上で実行されるので、VM上で動作するバイナリにコンパイルされます。
こうして出来上がったファイルをbeamファイルと呼びます。
作成したファイルは

````
$ erl -pz . -noshell -noinput -s モジュール名 関数名 -s init stop
````

とタイプしてターミナルで実行することができます。

しかし、手軽に実行させたい場合は`escript`を使用するほうが便利でしょう。

## escript

escriptではErlangのプログラムをPerlスクリプトのように実行することができます。

````{.erlang caption="Sample Erlang Code"}
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp enable -sname factorial -mnesia debug verbose
main([String]) ->
    try
        N = list_to_integer(String),
        F = fac(N),
        io:format("factorial ~w = ~w\n", [N,F])
    catch
        _:_ ->
            usage()
    end;
main(_) ->
    usage().

usage() ->
    io:format("usage: factorial integer\n"),
    halt(1).

fac(0) -> 1;
fac(N) -> N * fac(N-1).
````
````
$ chmod u+x factorial
````

````
$ ./factorial 5
factorial 5 = 120
````
````
$ ./factorial
usage: factorial integer
````
````
$ ./factorial five
usage: factorial integer
````
````
$ escript factorial 5
````
などとします。

詳しくはescript manual[^1]を参照してください。

[^1]: <http://erlang.org/doc/man/escript.html>



## 整数と実数
````
4> 2#0101.
5
5> 16#deadbeaf.
3735928495
````
のように`#`のまえに数字を置くことで36進数までN進数表記ができます。
Erlangは多倍長整数です。
浮動小数点数はIEEE754形式で$1.0e-323$から$1.0e+308$の範囲です。

## 文字列
文字はASCII文字の前に`$`を付けます。
````
7> $a.
97
````
文字列はダブルクォートで囲みます。これは文字のリストの糖衣構文です。リストは何かは後述します。

````
8> "a".
"a"
9> [$a,$b].
"ab"
````

Erlangの文字列は整数型のリストの糖衣構文であるため、多バイト文字は表現できません。
後述するバイナリで表現する必要があります。

## 変数
Erlangの変数名は大文字から始まります。

````
10> X = 1.
1
11> X.
1
````
これは変数`X`に`1`を代入して、`X`を評価しています。
代入については後述するパターンマッチで説明します。


## 演算子

### 算術演算子

* `+`
加算

* `*`
乗算

* `-`
減算

* `/`
除算

* `div`
整数の商

* `rem`
整数の商の余り

基本的にC言語やJavaと同じです。`div`と`rem`はそれぞれ整数で割ったときの商と余りです。

### 比較演算子

* `>`
大なり

* `<`
小なり

* `>=`
大なりイコール

* `=<`
小なりイコール

* `==`
等しい

* `/=`
等しくない

* `=:=`
等しい（型チェック付き）

* `=/=`
等しくない（型チェック付き）

### 論理演算子

* `not`
否定

* `and`
論理積∧

* `andalso`
論理積∧（短絡）

* `or`
論理和∨

* `orelse`
論理和∨（短絡）

* `xor`
排他的論理和


## 条件分岐

### if
````
if
    <条件式> -> <式1>;
    <条件式> -> <式2>
end
````
Erlangにはパターンマッチがあるため`if`はあまり使われません。
条件分岐は後述するパターンマッチの方をよく使います。

## アトム
アトムは識別子を表します。小文字英文字から始まる英数字か、記号を含む場合はバッククォートで囲む必要があります。

````
1> abc.
abc
````
もちろん変数に代入もできます。

````
2> X = abc.
abc
3> X.
abc
````
アトムは後述するタプルやメッセージなどをパターンマッチするときに便利なのでErlangプログラミングではよく使用されます。

## 出力
Erlangではコンソールへの出力は一般には`io:format`という関数を使って行います。

### io:format

Erlangによる書式つき出力は`io:format`をつかって行われます。C言語の`printf`に相当しますが、フォーマット付き出力の書式はCより[Common&nbsp;Lisp//コモン&nbsp;リスプ](Xaruby)に似ています。


````
io:format("~p~n",[Term]).
````


* `~p`
 プリティープリント
* `~s`
 文字列
* `~n`
改行
* `~d`
整数（10進数）

ErlangにはC言語のような可変引数がないのでリストを使います。


## パターンマッチ

### case節
````
case <式> of
    <パターン1> -> <式1>;
    <パターン2> -> <式2>
end
````
case節はパターンマッチの一番わかり易い形式です。

````
2> A = 3.
3
3> case A of 1 -> a; 2 -> b; 3 -> c end.
c
````

とすると`c`が返ります。
このようにC言語の`switch`文のように使うことも出来るのです。
この式から最後のパターンマッチの処理を除くとどうなるでしょうか？

````
4> case A of 1 -> a; 2 -> b end.
** exception error: no case clause matching 3
5>
````

このように例外が発生します。これはパターンマッチにマッチする条件がなかったと言う意味の例外です。

### ワイルドカード
では次のように変更するとどうでしょうか？
````
5> case A of 1 -> a; 2 -> b; _ -> c end.
c
````
`_`はワイルドカードといってあらゆる場合にマッチします。正規表現の`.*`に似ています。予期しない値などのエラー処理に使われることがよくあります。

### 単一代入
````
X = 1.
````
[　](p)先程代入といったのは実はパターンマッチなのです。
`=`演算子は左辺の式に対して右辺のパターンマッチを行う演算です。左辺の変数がまだ束縛されてなければ右辺の式を評価した値が束縛されます。
`=`の左辺式のパターンマッチが失敗するともちろん例外が発生します。

この例では数値型のような単純な型の場合ばかりなので有用性が分かりづらいと思います。
後述するリストやレコード、タプルなどと組み合わせることで非常に多様な使い方ができます。
パターンマッチはErlangの中核となる機能です。

## 関数
````
<関数名>(仮引数...) ->
<本体>.
````
例えば以下は引数に指定された変数をインクリメントする関数です。
````
inc(X) -> X+1.
````
このようにして関数定義を行います。

## 関数とパターンマッチング
Erlangは関数の引数にもパターンマッチを行うことができます。

````
signal(red) -> stop;
signal(blue) -> do;
signal(yello) -> carefull;
signal(_) -> error.
````

### 再帰
ErlangにはC言語における`while`文などのループ制御構文がないので、ループ処理は再帰で行います。
階乗を求める関数を書いてみます。
````
pow(1) -> 1;
pow(X) -> X*pow(X-1).
````

### 末尾再帰
末尾再帰という形式にすることによってループ処理を最適化できます。

````{.erlang caption="Sample Erlang Code"}
pow_tail(1,Ret) -> Ret;
pow_tail(X,Ret) -> pow_tail(X-1,X*Ret).
````
[　](p)末尾再帰形式とは簡単にいうと、再帰関数の帰り値を評価しないのでスタックフレームに関数の戻り先を毎回積まなくてもいいので、
内部で`while`ループのように扱えるのです。気になった人は自分で勉強してください。

## レコード
いわゆる構造体です。

````
-record(<レコード名>, {<要素名1>,<要素名2>,...}).
````

レコードを定義する`rd`関数と言う糖衣構文も用意されています。

````
rd(item, {id,name,price}).
````

````
7> rd(player, {name,hp}).
player
`````

### 初期化

````
#<レコード名>{<要素名1>=初期値1, <要素名2>=初期値2,...}
````

といった形でレコードの初期化が可能です。


````
9> P = #player{name="hoge", hp=3}.
#player{name = "hoge",hp = 3}

````

### 参照
````
変数#<レコード名>.<要素>
````
と言った形で参照します。

````
10> P#player.name.
"hoge"
````

### 変更

`````
変数#<レコード名>{<要素>="hage"}.
`````

とすることでレコードの要素を変更したレコードを返します。

````
11> P#player{name="hage"}.
#player{name = "hage",hp = 3}
````
### レコードのパターンマッチ

左辺に、

```
#<レコード名>{<要素名1>=値,<要素名2>=変数名,..}
```

と言った形でパターンマッチできます。

```
2> P = #item{id=1,name="test",price=100}.
3> #item{id=1} = P.
#item{id = 1,name = "test",price = 100}
4> #item{id=1,name=Name} = P.
#item{id = 1,name = "test",price = 100}
5> Name.
"test"
```

## リスト
````
[<要素1>,<要素2>...]
````
````
1> [1,2,3].
[1,2,3]
````

これはLispなどのリストと同じリストです。内部的にはLispと同様`cons`セルによる再帰構造で最後が`nil`となっています。この事は後述します。

### リスト処理
リストはパターンマッチで処理が可能です。
次にリストの長さを計算する関数を例として載せます。

```{.erlang caption="Sample Erlang Code"}
len([]) ->
    0;
len([Head|Tail]) ->
    1+len(Tail).
```

`[]`は空のリストにマッチします。
`[Head|Tail]`の`Head`はリスト先頭、たとえば`[1,2,3]`とあったら`1`にマッチして`Tail`は`[2,3]`にマッチします。

リストを処理する関数は標準ライブラリの`lists`というモジュールにまとめられています。

## タプル
````
{<要素1>,<要素2>...}
````
````
1> {1,2,3}.
{1,2,3}
````
タプルはErlangではLispのS式代わりに使われることが多いです。

## バイナリ
````
<< <値1>:<サイズ1>/<タイプ>, <値2>:<サイズ2>/<タイプ> ...>>
````
というふうにかいて値をサイズ毎に指定できます。サイズ指定を省略するとデフォルトの8ビットになります。
このサイズの大きさごとに分割された塊をセグメントと呼びます。

タイプは型、符号、エンディアンが指定でき、複数のタイプを`-`で連結できます。
指定可能な型を以下に載せます。

型

* `integer`
整数
* `float`
浮動小数点
* `binary`
バイナリ型
* `bytes`
バイト型
* `bitstring`
ビットストリング
* `bits`
ビット型
* `utf8`
UTF-8のビットストリング
* `utf16`
UTF16のビットストリング
* `utf32`
UTF32のビットストリング

符号

* `signed`
符号付き

* `unsigned`
符号なし

エンディアン

* `big`
ビッグエンディアン

* `little`
リトルエンディアン

* `native`
CPUネイティブの エンディアン

* `unit`
セグメントのサイズ

### バイナリ演算子

* `bsl`
左シフト
* `bsr`
右シフト
* `band`
bit論理積
* `bor`
bit論理和
* `bxor`
bit排他的論理和
* `bnot`
bit論理否定

### バイナリのパターンマッチ
バイナリのパターンマッチの例としてRGBカラーの例を載せます。

```
1> Color = <<16#FF00FF:(8*3)>>.
<<255,0,255>>
```

としてRGBのそれぞれの8ビットを`,`で区切って定義することができます。

```
2> <<R,G,B>> = Color.
<<255,0,255>>
```

この様にパターンマッチによって8ビットごとに分解したりすることができます。

先頭のRだけほしい場合は、ワイルドカードを使って次の様に書くことで取得できます。

```{.erlang caption="Sample Erlang Code"}
2> <<R:8,_/binary>> = Color.
<<255,0,255>>
3> R.
255
```

余談ですが、Erlangで日本語のような多バイト文字を扱うには

```{.erlang caption="Sample Erlang Code"}
io:format("~ts~n",[<<"お"/utf8>>]).
```

のようにバイナリ形式でUTF-8を指定する必要があります。詳しくはErlangのドキュメントをご覧ください。[^erlang-bit-syntax]

[^erlang-bit-syntax]: <http://erlang.org/doc/programming_examples/bit_syntax.html>

## 内包表記
内包表記にはリスト内包表記とバイナリを内包表記の二種類があります。
もともとは、内包表記とは集合論において条件Pに合致する要素を集めた集合を表現する記法です。
これを表現しようとした記法がMirandaに取り入られました。この記法は後にHaskellや[Pythonにも取り入れられています。

### リスト内包表記
`erl`に

````
Erlang R16B03 (erts-5.10.4) [source] [64-bit] [async-threads:10] [kernel-poll:false]

Eshell V5.10.4  (abort with ^G)
1> [ X*2 || X<-[1,2,3,4,5], X<4 ].
````

と打ち込んでみてください。
すると、

`````
[2,4,6]
`````
帰ってくるはずです。
これは、`X<-[1,2,3,4,5]`によって、リストが生成されます。
次に、条件`X<4`に合致する`1,2,3`がフィルタリングされ、
最後に式`X*2`によって`1*2,2*2,3*2`のリストが作られたということです。

一般化すると次のようになります。

````
[式 || パターン <- リスト, 条件]
````

### バイナリ内包表記
バイナリ内包表記は内包表記のバイナリ版です。

````
 <<式 || パターン <= バイナリ, 条件>>
````

## 並列
Erlangにおいて並列処理は、軽量プロセス（以下プロセス）とメッセージによって実現されています。
ErlangのプロセスはOSのプロセスに似ていますが、ErlangのVMで実行されるのでOS内部でのコンテキストスイッチが行われません。
Erlangのプロセス同士はメモリ領域を共有せずにメッセージ・キューを通じて通信を行います。
Erlangのプロセスはレジスタの一時退避やカーネルモードへの切り替えなどの複雑なコンテキストスイッチを伴わないため切り替えは高速です。

### アクターモデル
Erlangの並列モデルであるアクターモデルにについて簡単に紹介します。
メッセージを送受信できるアクターと呼ばれるオブジェクトが、メッセージを非同期に送受信することによって、
並列的に計算処理を行う計算モデルです。Erlangにおいてはプロセスがアクターに相当し、お互いにメッセージを送受信しています。
このアクターモデルの概念はErlang以外にもScalaのフレームワーク等に採用されています。

### spawn

`spawn`は次の様な形で呼び出して軽量プロセスを生成します。

````
Pid = spawn(<モジュール名>, <関数名>, <引数のリスト>)
````

`spawn`は引数の関数からプロセスを生成し、プロセスIDと呼ばれるプロセス毎にユニークな数値を返します。
プロセスIDとプロセスは紐付いていて、プロセス間におけるメッセージの送受信の際にこのプロセスIDを使用します。


### メッセージの送信

メッセージの送信は次の様に送信したいプロセスのプロセスIDに`!`メッセージという形式でメッセージを送信します。

````
Pid ! メッセージ
````

### メッセージの受信

次の様に`receive`でメッセージを受信し、パターンマッチでメッセージに対応する処理を行うのが一般的です。

````
receive
    <パターン1> ->
        <処理1>;
    <パターン2> ->
        <処理2>;
    ............
    <パターンN> ->
        <処理N>
    after n ->
        <タイムアウト処理>
end
````
`after`はnミリ秒たった時のタイムアウト時の処理をします。

### プロセス登録

`spawn`が生成するプロセスIDをいちいちプログラマが変数で保存しておくのは面倒です。特に複数のプロセスがメッセージを送るプログラムを作るときは管理がとても面倒になります。
ErlangにはプロセスIDではなく、アトムを指定してメッセージを送る方法があります。
それがプロセス登録です。プロセスを登録するには`register`関数を使用します。
本書の範囲を超えるので詳しくは述べませんが、プロセス登録機能は分散環境ではよく使用します。

````
register(Atom,Pid)
````
とすることで、
`Atom` `!` メッセージ
と言った形でアトムを使って登録したプロセスにメッセージが送信できます。

## spawn_link

`spawn_link`は基本的に`spawn`と同じですが、例外が発生した場合の動作が異なります。
生成した子プロセスで発生した例外をプロセスが作成した側の親プロセスも受け取ります。
`spawn`の場合、親プロセスは例外を受け取りません。

## 例外

例外は次の様にして書きます。

````
try <評価される式> of
    <パターン1> ガード1 -> <処理1>;
    <パターン2> ガード2 -> <処理2>
catch
    <例外のタイプ1>: <パターン1> ガード1 -> <例外処理1>;
    <例外のタイプ2>: <パターン2> ガード2 -> <例外処理2>
after
    <例外が起きても起きなくても実行される処理>
end
````

`try ... of`で囲まれた式において例外が発生すると`catch`以降でパターンマッチが行われ、例外処理が実行されたあとに`after`の処理が行われます。

次は例外を発生させる関数です。

### throw

次の様にして例外を発生させることができます。

````
throw(<式>)
````

## exit

次の様にして例外を発生を起こし、プロセスを終了させます。

````
exit(<式>)
````

## error

次の様にして重大な例外を発生させ、プロセスを終了させます。
`error`は主にEralngのVMが生成するランタイムエラーとして使用されます。

````
error(<式>)
````


## モジュール

モジュールはソースを記述するファイル単位でコンパイルする際の最小単位です。ソースは何らかのモジュールに属していないとコンパイルできません。
モジュールを作成するには`.erl`ファイルに
モジュール宣言などのモジュール属性を記述する必要があります。

### モジュール属性

モジュール属性はファイルの先頭によくある`-`から始まる宣言です。
たとえば、モジュール宣言などがあります。

#### モジュール宣言

````
-module(<モジュール名>).
````

#### エクスポート宣言
エクスポート宣言する関数を宣言します。
次の様に関数名と引数の数を`/`でつなげてください。
````
-export([<関数名>/<引数の数>])
````
次の様にすればモジュールで作成した全ての関数をエクスポートできます。
````
-export_all
````

#### コンパイルオプション宣言

コンパイラに指定するオプションです。[^erlang-compiler-options]

[^erlang-compiler-options]: <http://erlang.org/doc/man/compile.html>

#### マクロ定義

次の様にしてマクロを定義できます。

````
-define{<マクロ>,<式>}
````

#### レコード宣言

次の様にしてレコードを宣言できます。

````
-record(<レコード名>, {<要素名1>,<要素名2>,...}).
````

### インクルード

次の様にしてヘッダファイルをインクルードできます。

````
-include("<ヘッダファイル>").
````

ヘッダファイルの拡張子は`.hrl`です。