関数型プログラミング言語Erlang を触ってみました。(『7つの言語 7つの世界』第6章)

7つの言語 7つの世界』(オーム社)の第6章で紹介されているErlangです。
Erlang
http://www.erlang.org/
 
 この第6章のErlangからこの本では、第7章のClojure、第8章のHaskellと関数型言語が続きます。先のエントリで紹介した第5章のScalaもあわせると7つのうち、関数型言語に4つも割かれています。著者のの関数型言語への関心の高さと関数型言語に対する注目の高さが伺えます。

1.Erlangについて

Erlang(アーラン)はEricsson Languageの略で、その名前にあるとおり、Ericsson社が開発した関数型言語です。Prologをベースに開発されました。耐障害性と並行性が大きな売りになっているようで、Erlangの「プロセス」が大きくそれに貢献しているようです。
プロセス / Erlang World
 ErlangのMacOS X LionへのインストールはHomebrewを使用しました。2012年6月12日時点でバージョンはR15B01です。

$ brew install erlang

 

2.Hello,World

 ターミナルで「erl」と打つとErlangのシェルが起動します。

$erl
Erlang R15B01 (erts-5.9.1) [source] [64-bit] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.1  (abort with ^G)
1>

 ちなみに終了は「 q().」。最初、これが分からず難儀しました。

1> q().
ok
$

  
基本的な書き方ですが、行末は必ずピリオド(.)をつける。コメントはパーセント記号(%)(行末のピリオドは不要)

2>%数値
2> 1+1.
2
3>%文字列
3> "Hello,World".
"Hello,World"
4>%数値と文字列を加算してみると・・
4> 1+"1".
** exception error: bad argument in an arithmetic expression
     in operator  +/2
        called as 1 + "1"

 

3.変数とアトム(シンボル)

 
 変数は大文字で始まる文字列で定義します。小文字で始まる文字列は後述する「アトム」というシンボルを表すため、変数として使えません。

5> A = 1.
1
6> a = 1.
** exception error: no match of right hand side value 1

 
 Scalaは変更不可能な変数と変更可能な変数を選ぶことができましたが、Erlangでは変更不可能な変数しか定義することができません。

7> A = 2.
** exception error: no match of right hand side value 2

 小文字で始まる文字列で「アトム」というシンボルを表します。Rubyでいうところのコロン(:)をつけた例えば”:name”、”:price”みたいなものです。

8> hello_world.
hello_world

 
 シングルクォーテーション(’)で囲うと大文字から始まる文字列もアトムとして扱われるようです。シングルクォーテーション(’)とダブルクオーテーション(“)のどちらで囲っても文字列として扱われるRubyに慣れていると少し戸惑います。

9>'Hello_world'.
'Hello_world'

4. リストとタプル

 Erlangには、Prologと同じようにリストとタプルという配列が用意されています。リストは角括弧[ ]で囲われた可変長の配列で、タプルは中括弧{ }で囲われた固定長の配列です。Prologではタプルを()で囲うところが違いますね。

10>%リスト
10>[1,2,3,4,5]
[1,2,3,4,5]

 Erlangは文字列を実はリストとして扱っています。そのため、以下のような整数のリストから文字列を返してくる。

11> [72,101,108,108,111,44,87,111,114,108,100].
"Hello,World"

 ちなみに上の数字はそれぞれASCIIコードです。日本語対応していない処理系を使用すると英数字以外を入力するとそのままリストで返されてしまいます。以下はユニコード表の数字ですね。

12> "ドラゴンボール".
[12489,12521,12468,12531,12508,12540,12523]

 

4. タプルとパターンマッチ

 ErlangにはRubyでいうハッシュのようなものがないようですが、タプルで以下のように書くことができます。book、title、author、publisherはアトムでハッシュでいうところのキーとして使用しています。

13> {book,{title,"Dragon Ball"},{author,"Toriyama Akira"},{publisher,"Syueisya"}}.
{book,{title,"Dragon Ball"},
      {author,"Toriyama Akira"},
      {publisher,"Syueisya"}}

上のタプルをBookという変数に代入します。

14>  Book = {book,{title,"Dragon Ball"},{author,"Toriyama Akira"},{publisher,"Syueisya"}}.
{book,{title,"Dragon Ball"},
      {author,"Toriyama Akira"},
      {publisher,"Syueisya"}}

今度は上と同じ構造で”Dragon Ball”等の文字列を入れていたところを変数に置き換えたタプルに上のタプルを変数Bookを経由して代入させます。

15> {book,{title,Title},{author,Author},{publisher,Publisher}} = Book.
{book,{title,"Dragon Ball"},
      {author,"Toriyama Akira"},
      {publisher,"Syueisya"}}

 するとデータ構造でマッチさせることで、それぞれの変数にそれぞれの値が代入され、以下のように取り出すことができます。

16> Title.
"Dragon Ball"
17> Author.
* 1: variable 'Author' is unbound
18> Author.
* 1: variable 'Author' is unbound
19> Publisher.
"Syueisya"

5. 関数

テキストエディタで以下のように「test.erl」というerlという拡張子を持つファイルを作成します。

%-moduleでモジュール名(この場合はtest.erlの拡張子を取り除いたもの)を定義。
-module(test)
%関数名を定義(/1の1は引数の数)
-export([print/1])
%以下から関数を定義
print(A) -> A

Erlangシェルを起動して「test.erl」をコンパイルします。

1> c(test).
{ok,test}

  コンパイル後にtestモジュールのprint関数が利用できるようになります。

2> test:print("Hello World").
"Hello World"

 

5.1. 無名関数

funという関数で無名関数、つまり名前のない関数を定義できます。

3>fun(A) -> A end.
#Fun<erl_eval.6.82930912>

 
この無名関数を変数に代入できます。

4>Print = fun(A) -> A end.
#Fun<erl_eval.6.82930912>
5>Print("Hello, World").
"Hello, World"

 

5.2. 高階関数

 関数を引数として受け取ったり、戻り値として返す高階関数。関数を戻り値として返すというのはこういうことでしょうか。

6>HighPrint = fun(X) -> Print(X) end.
#Fun<erl_eval.6.82930912>

  関数を引数として受け取る。下ではまずTestというリストを作成し、リストの要素を順番にPrint関数に引数として渡しています。戻り値もそのままリストになってしまうので分かりづらいですが、”Hello”、”World”、”Erlang”という戻り値が返ってきてます。

7> Test = ["Hello","World","Erlang"].
["Hello","World","Erlang"]
8> lists:map(Print,Test).
["Hello","World","Erlang"]