Elixir : Erlang VM 上で動作する Ruby 風味の関数型言語

Elixir は Erlang VM (BEAM) 上で動作する Ruby 風の関数型言語です。
今回はこの Elixir の特徴を紹介した後、 Windows へのインストールと簡単な使用法、および Emacs の Elixir 用モードの設定について説明したいと思います。

elixir_logo.png

Elixir とは

Elixir の前に Erlang について触れておきます。
Erlang は Java のように仮想マシン(VM)を使った関数型言語です。 Erlang はリアルタイム並列処理などに適しており、 特に耐障害性の高いシステムを求められるときに使います。
Erlang はサーバーサイドの言語として Java とはまた違った魅力があるのですが、 一つ難点があります。
それは Erlang が Prolog 風の構文を採用しており、癖が強く、 かなり書きづらい点です。 では、逆に現時点でもっとも書きやすい言語は何でしょうか ?
そう、 Ruby ですね。

まぁ、これは私の独断と偏見ですが、他にもそう思っている人は多いでしょう。
実際に Reia という Elang VM 上で動作する Ruby 風の言語が登場しました。
しかし、 残念ながら Reia の開発は終了してしまいました。 終了のお知らせとともに、代わりとして強く勧められているのが Elixir です。 ただ、 Reia と比べると Elixir は Erlang よりです。 そこは惜しいところですが、 そのかわりに 関数型言語になっています。
Ruby っぽさのある関数型言語ってすごく魅力的ではないでしょうか。


ちなみに Elixir は "エリクサー" と発音されるようです。
エリクサーは RPG ゲームでは HP, MP をフル回復するアイテムとして出てきます。 全ての病を治す霊薬だったり、飲むと不老不死になったり、 錬金術の賢者の石的な液体だったりと 伝説的な薬 を指すときに使われる言葉みたいです。
若干、大風呂敷を広げちゃった感はありますが、意気込みを買いましょう。

特徴

本家サイトのサンプルを引用しつつ、 Elixir の特徴を説明していきます。

Hello, world!

hello.exs :
defmodule Hello do

  def world do
    IO.puts "Hello World"
  end

end

Hello.world
Hello World
サンプルを見てもらうとわかりますが、 確かに Ruby っぽい構文です。 ただ、オブジェクト指向ではないので、 クラスではなくモジュールとなっています。


コメントを含めて、日本語を使用する場合には BOM なしの UTF-8 を使う必要があります。
日本語を文字列としても使えるようですが、 ターミナルも対応していないと文字化けしてしまいます。

全てが式

"全てが式(関数)" というのは、 Lisp 的な考え方です。
通常、制御文として扱われる if などもマクロを使って定義されたです。
例えば、 if の反対である unless のような制御キーワードが欲しければ、 自分でマクロを定義して増やすことができます。 (実際にはすでに unless はあります)
defmodule MyMacro do
  defmacro unless(clause, options) do
    quote do: if(!unquote(clause), unquote(options))
  end
end

var = false
MyMacro.unless var do
  IO.puts "false"
end

メタプログラミングと DSL

メタプログラミング(リフレクション)とは、プログラム内でプログラム自身を変更できる機能で Ruby などが得意としているところです。
プログラムが自分自身を見れるため、メンバーである関数や値などの取得、実行ができて、 テストやデバッグに便利です。

Elixir のメタプログラミングはさらに一段上を行っています。 制御文も式なので、構文さえいじることができます。
(Lisp はいじれすぎて、方言が大量にできる原因になったりもしてますが)

一方、ドメイン固有言語(Domain-Specific Language 、 DSL) は Makefile といったビルド定義ファイルや Config ファイルのように特定用途の定義に使われる言語です。
構文の改造を駆使して Elixir を DSL として使うことができます。

実際、 Elixir ではメタプログラミングを利用した ExUnit という単体テストのフレームワークがあります。
defmodule MathTest do
  use ExUnit.Case

  test "can add two numbers" do
    assert 1 + 1 == 2
  end
end

プロトコル(文脈, 約束)による多様性

これは Lisp の方言である Clojure に似た機能があります。

オブジェクト指向における多様性は、メソッドを呼び出した際にオブジェクトにあわせて 呼ばれるメソッドが変わることを言います。
Elixir も対象にあわせて呼ばれる関数が変わります。


例えば、 Enum モジュールに map という関数が用意されています。
これは Ruby の Enumerable#map のような機能です。 コレクションの各要素に関数を適用し、 その結果を集めた新しいコレクションを返します。
Enum.map([1,2,3], fn(x) -> x * 2 end) #=> [2,4,6]
この map はファイルのイテレーターに対しても使用することができます。
file  = File.iterator!("README.md")
lines = Enum.map(file, fn(line) -> Regex.replace(%r/"/, line, "'") end)
File.write("README.md", lines)
この辺は C++ にある STL のイテレーターにも似ています。

ドキュメントもコードの一部

コメント上に説明を書いて、 Doxygen のようなツールでドキュメントを作成することが最近では普通になってきました。
Elixir では関数説明などをコメントではなく、直接コードの一部として書けます。 これは Lisp や Python にある機能で、 特に Emacs Lisp では大活躍しています。
defmodule MyModule do
  @moduledoc """
  Documentation for my module. With **formatting**.
  """

  @doc "Hello"
  def world do
    "World"
  end
end
定義したドキュメントは対話モードでのヘルプコマンド h() などで見ることができます。
iex(1)> h MyModule
# MyModule

Documentation for my module. With **formatting**.
:ok
iex(2)> h MyModule.world
* def world()

Hello
ただ、 Elixir にも ExDoc というドキュメント生成ツールがそれはそれとして用意されています。

パターンマッチング

Elang 由来、さらに言えばその元の Prolog 由来の機能です。 Ruby ユーザーにはなじみのない機能ではないかと思います。
ただ、 関数型言語では結構使われているようです。
iex(1)> [a, b] = [1, 2]
[1,2]
iex(2)> a
1
iex(3)> b
2
iex(4)> [head | tail] = [1, 2, 3]
[1,2,3]
iex(5)> head
1
iex(6)> tail
[2,3]
[head | tail] のようなマッチと再帰を組み合わせてよく使用されます。
defmodule Printer do
  # 1 回目は head = "foo", tail = ["bar", "baz"] でマッチ
  def print([head|tail]) do
    IO.puts head
    print(tail) # 再帰呼び出し。 1 回目は print(["bar", "baz"])
  end

  # リストが空になったときにマッチ
  def print([]) do
    # 何もしない。
  end
end

Printer.print ["foo", "bar", "baz"]
foo
bar
baz

結局のところ Erlang

JRuby のような JVM 言語では Java のクラスを使えます。 同じように Elixir では Erlang の関数を自由に呼び出すことができます。
:application.start(:crypto)
:crypto.md5("Using crypto from Erlang OTP")
#=> <<192,223,75,115,...>>
Erlang には、 OTP というフレームワークがついてきます。 これにはリアルタイム並列システムを作るのに役立つライブラリーが詰まっています。
このライブラリーを Elixir からも利用できます。

インストール

ここからはインストールと使い方について説明していきたいと思います。
Elixir について興味をもった場合は、 ぜひ使って試してみて下さい。


先に Erlang をインストールする必要があります。 Erlang のインストールについては以前の記事をご覧下さい。 次にダウンロードページから最新版のパッケージ(vX.X.X.zip)をダウンロードします。 lang_elixir_dl.png

パッケージを展開して、その中の bin フォルダーを環境変数 Path に登録します。

使い方

Erlang と同様に 3 つの方法で使用することができます。
モードごとの実行ファイル(bat ファイル)とソースファイルで使用される拡張子は以下のようになっています。
モード 実行ファイル 拡張子
対話モード iex ---
コンパイル elixirc .ex
スクリプト elixir exs

インストールした中にはこの他に mix という実行ファイルが入っています。 mix は Clojure の leingen 風のビルドツールです。 こちらについては解説しないので、以下のページなどを見てください。

対話モード

コマンドライン上で iex.bat を実行すると対話モードとなります。
~/lang/elixir $ iex
Interactive Elixir (0.9.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> 1 + 1
2
iex(2)> IO.puts "Hello"
Hello
:ok
ただ、文字の装飾用の制御コードが入っているので、変な字が出てきます。
eshell 上では多少は対応していますが、 ちゃんと使うには Unix 系のターミナルソフトを使う必要があるんじゃないかと思います。


終了用のコマンドは用意されていないようなので、 最初のメッセージに出ているように Ctrl+C で終了するしかありません。

対話モードでは h() でヘルプが表示されますが、 -h や --help で iex のコマンドラインのヘルプを表示することはできません。(Ver. 0.9.2)
チケットでは対応済みなので、そのうち使えるようになるとは思います。

コンパイル

Java の class ファイルのように、コンパイルして中間ファイルを作成し、使用することができます。 中間ファイルの拡張子は beam です。

次のようなサンプルを用意します。

math.ex :
defmodule Math do
  def sum(a, b) do
    a + b
  end
end
これを elixirc.bat でコンパイルすると Elixir.Math.beam ファイルが作成されます。
iex を実行すると、カレントフォルダーにある beam ファイルが自動的にロードされます。

サンプルの実行 :
~/lang/elixir/sample $ elixirc.bat math.ex
Compiled math.ex
~/lang/elixir/sample $ ls
Elixir.Math.beam  math.ex
~/lang/elixir/sample $ iex
Interactive Elixir (0.9.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Math.sum(1, 2)
3
カレントフォルダー以外の beam ファイルを使いたい場合には -pa オプションで指定します。
~/lang/elixir/sample $ iex -pa ebin
elixirc は引数なしで実行するとヘルプを表示することができます。


実際のアプリケーションでは スクリプトなどの他のファイルから呼び出して使うことになるでしょう。
その場合には require でモジュールを指定してロードします。
require Math

スクリプト

elixir(.bat) の引数にソースファイル(.exs)を渡すとスクリプトモードで実行します。
 ~/lang/elixir $ elixir.bat hello.exs
elixir も引数なしでヘルプ表示です。
perl や ruby のように -e によるワンライナーも使えるようです。

Emacs モードの設定

Elixir 用モードはパッケージが作成されています。 elixir-mode のパッケージを選択してインストールします。

インストールすると *.ex や *.exs のファイルを開いた時に elixir-mode になろうとはします。
しかし、 elixir-mode が未定義というエラーが出るので、 以下の記述を ~/.emacs.d/init.el に追加する必要があります。
;; Elixir
(autoload 'elixir-mode "elixir-mode"
  "Major mode for editing Elixir files." t)
ただ、
出るはずのメニューが出なかったり、
elixir-mode-compile-file のコマンドに失敗したり、
コメントのシンタックスが設定されていなかったり、
インデントの挙動がおかしかったり
...
とバグでボロボロです。

かろうじて M-x elixir-mode-iexで iex の呼び出しはできるようでした。


インデントの挙動がおかしいのは、もう致命的です。 しょうがないので、応急処置として以下の記述でインデントできるようにしています。
あとついでに elang-mode のように C-c C-l で対話モードを起動できるようにしています。
(add-hook 'elixir-mode-hook '(lambda ()
                               (local-set-key "\\t" 'elixir-mode-indent-line)
                               (make-local-variable 'default-tab-width)
                               (setq default-tab-width 2)
                               (local-set-key "\C-c\C-l" 'elixir-mode-iex)))
他にも直すべきところはいろいろあるのですが、 ちゃんと修正するなら ruby-mode を改造して作り直した方がおそらく早いでしょう。


また、 M-x compile でコンパイルした時、 エラー行をうまく認識してくれません。
以下の記述も追加するとエラー行を認識してジャンプ等ができるようになります。
(require 'compile)
(setq compilation-error-regexp-alist
      (append 
       '(;; ** (TokenMissingError) d:/home/lang/elixir/sample/math.ex:5: 
         ("^\\*\\* ([^)]+) \\(.*\\):\\([0-9]+\\): " 1 2)) compilation-error-regexp-alist))

感想

Elixir は "見た目は Ruby 、 中身は Lisp" といった感じの言語でした。
もともと Ruby も Lisp 感漂う言語ですが、それが顕著になっています。

Erlang に比べれば、断然書きやすくなっているうえに、関数型で並列処理の強い点などの良さも残しています。 Erlang を使うならば、 Elixir を使った方がいいと思います。


Elixir は言語仕様的には素晴らしいと感じました。ただ、実際に使うかどうかは目的によりけりです。
Erlang VM (BEAM) には高い信頼性はありますが、速度の面では JVM の方が優れています。 Erlang を開発したエリクソンのような電話会社などには信頼性の方が大事なのかもしれません。
速度は他の要素とトレードオフなのところがあります。 Ruby では"書きやすさ"を優先させて設計されている感があります。

信頼性は高いに越したことはありませんが、 個人的には速度を犠牲にしてまでシビアに要求されるものを作ることは今のところありません。 速度を重視するなら JVM 言語や Native 言語、 開発効率を求めるなら Rails と、 あまり出番がないです。

JVM や .NET 向けの Elixir 実装がでるといいんですけどね。 そしたら多分、飛びつくんじゃないかと思います。

参考

関連記事
スポンサーサイト
Prev.    Category    Next 

Facebook コメント


コメント

No title

”メタプログラミング(リファクタリング)”となっているところがありますが、リフレクションではないでしょうか?

Re: No title

> ”メタプログラミング(リファクタリング)”となっているところがありますが、リフレクションではないでしょうか?

ご指摘ありがとうございます。確かにその通りです。
記事を修正しました。

コメントの投稿

Font & Icon
非公開コメント

このページをシェア
アクセスカウンター
アクセスランキング
[ジャンルランキング]
コンピュータ
43位
アクセスランキングを見る>>

[サブジャンルランキング]
プログラミング
3位
アクセスランキングを見る>>
カレンダー(アーカイブ)
プルダウン 降順 昇順 年別

05月 | 2017年06月 | 07月
- - - - 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 -


はてな新着記事
はてな人気記事
ブロとも申請フォーム
プロフィール

yohshiy

Author:yohshiy
職業プログラマー。
仕事は主に C++ ですが、軽い言語マニアなので、色々使っています。

はてブ:yohshiy のブックマーク
Twitter:@yohshiy

サイト紹介
プログラミング好きのブログです。プログラミング関連の話題や公開ソフトの開発記などを雑多に書いてます。ただ、たまに英語やネット系の話になることも。