もう一つのErlang VMベース言語、LFE(Lisp Flavored Erlang)をRaspberry Pi2で試してみた

**LFE**, Erlang関係で聞いたことはあったけど調べ物していて見かけたので試してみました。
どうせならRaspberry Pi2に入れてみようとしたらちょっと苦労したのでメモ。

-----

## LFE(Lisp Flavored Erlang)とは

その名の通り、見た目が**Lisp**の**Erlang**です。[**本家のサイトはこちら**](http://lfe.io/)。

**Elixir**が「Erlang VM上で動くRuby風の新しい言語」として設計されたのと異なり、**LFE**は「関数名やその中身はErlangのまま、見た目は完全にLisp」として設計されています[^1]。

[^1]: Lispは長い歴史上「何かのアプリの設定・操作用のDSL」として使われたことが幾度もあり(最も有名な例はEmacsでしょう)、Erlang VMを使うためのDSLみたいなものと考えれば自然な気がします。元々方言も多いですしね。

Qiitaでも過去に[(lisp (flavored (erlang)))について基本その1](http://qiita.com/nobkz/items/2be2b6806237d8ea6e21)や[Lisp Flavored Erlang (LFE) のインストール](http://qiita.com/masato/items/8fcd61bda7934d28230b)などの記事がありますのでそちらも見てもらったほうがいいと思います。

## Raspberry Pi2 (Raspbian) に LFE をインストールする

LFEのインストールは[**LFE-Quick Start/Getting LFE**](https://lfe.gitbooks.io/quick-start/content/1.html)を見ると真っ先に[**homebrew**](http://brew.sh/)を使うのやり方が出てくるのでこれが良さ気です。

MacOSXでは`brew`コマンドをしょっちゅう使っているのに、Linuxに似たようなシステムがあるとは全然知りませんでした。

### Linuxbrewのインストール

まずLinux用のbrewを[**ここ**](https://github.com/Homebrew/linuxbrew)に従って設定します。

#### 必要なプログラム、ライブラリをapt-get install する。

```bash
$ sudo apt-get install build-essential curl git m4 ruby texinfo libbz2-dev libcurl4-openssl-dev libexpat-dev libncurses-dev zlib1g-dev
```

#### Linuxbrewをインストールする

```bash
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/linuxbrew/go/install)"
```

以下をインストールしていいか聞いてくるのでRETURN。

```bash
==> This script will install:
/home/azureuser/.linuxbrew/bin/brew
/home/azureuser/.linuxbrew/Library/...
/home/azureuser/.linuxbrew/share/man/man1/brew.1

Press RETURN to continue or any other key to abort
==> Downloading and installing Homebrew...
...

```

### 環境変数を設定する

下記を.bashrcや.bash_profileなどに追加します。

```bash
export PATH=$HOME/.linuxbrew/bin:$PATH
export MANPATH=$HOME/.linuxbrew/share/man:$MANPATH
export INFOPATH=$HOME/.linuxbrew/share/info:$INFOPATH
```

忘れないように

```bash
$ source ~/.bashrc
```

のように環境変数をセットしておきましょう。

#### Linuxbrewの初期化

```bash
$ brew doctor
```

以上で設定完了です。

### lfeのインストール

上記のGetting LFEのページではこのあと

```bash
$ brew install lfe
```

でオシマイ、となっていましたが…　途中で失敗します[^2]。

[^2]: 肝心な依存モジュールであるErlang自体が入らないのでElixirも同じ問題でbrewでのインストールに失敗します。

```bash
$ brew install lfe
==> Installing dependencies for lfe: wxmac, erlang, rebar
...
==> Installing lfe dependency: wxmac
==> Downloading https://downloads.sourceforge.net/project/wxwindows/3.0.2/wxWidgets-3.0.2.tar.bz2
...
checking for architectures to use in universal binary...
checking if C compiler (/usr/bin/gcc-4.9 -mmacosx-version-min=0) works with SDK/version options... configure: error: in `/tmp/wxmac20151025-330-1o2c8rv/wxWidgets-3.0.2':
configure: error: no.  Try a different SDK
See `config.log' for more details

READ THIS: https://github.com/Homebrew/linuxbrew/blob/master/share/doc/homebrew/Troubleshooting.md#troubleshooting
```

**wxmac**が入らない、と言われてエラーになります[^3]。

[^3]: もちろん本家MacOSX用のhomebrewでは全く問題なしでした。

回避策は[**ここ**](https://github.com/Homebrew/linuxbrew/issues/512)にありました。wxmac(=wxwidget)はGUI用のライブラリです。とりあえず試しに動かす分には不要なので、先に**lfeが依存するErlangをwxwidgetなしでbrewしてしまいます**。

```bash
$ brew install erlang --without-wxmac
$ brew install lfe
```

## LFEを起動していじってみる

LFEにもREPLがあるので起動していじってみます。

#### Hello, Worldなど

```bash
$ lfe
Erlang/OTP 18 [erts-7.1] [source] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

LFE Shell V7.1 (abort with ^G)
>  (io:format "Hello, World~n")
Hello, World
ok
```

Erlangの同等のコードが

```erlang
io:format("Hello, World~n").
```

なので確かに見た目はLisp, 中身はErlangですね。

もうちょっといじってみます。1から100まで足すのは

```cl
> (lists:foldl (lambda (n acc) (+ n acc)) 0 (lists:seq 1 100))
5050
```

こんな感じ。これもErlangの`lists:foldl/3`、`lists:seq/2`がそのまま出てきています。

#### FizzBuzz

もういっちょ。よくあるFizzBuzz問題。

```cl
(defun fbcheck (x)
     (cond ((and (== (rem x 3) 0) (== (rem x 5) 0))  "FizzBuzz")
           ((== (rem x 3) 0) "Fizz")
           ((== (rem x 5) 0) "Buzz")
		   ('true (integer_to_list x))))
(defun fizzbuzz (x)
    (lists:map (lambda (x) (fbcheck x)) (lists:seq 1 x)))
...
(fizzbuzz 100)
("1"
 "2"
 "Fizz"
 "4"
 "Buzz"
 "Fizz"
 "7"
 "8"
 "Fizz"
...
```

Lispとしてどうなのよ？ということでlfeと同じLisp-2(関数と変数の名前が別の名前空間)である**Common Lisp**と比較してみます。

```cl
(defun fbcheck (x)
  (cond ((and (= (mod x 3) 0) (= (mod x 5) 0)) "FizzBuzz")
        ((= (mod x 3) 0) "Fizz")
        ((= (mod x 5) 0) "Buzz")
        (t  (format nil "~a" x))))
(defun fizzbuzz (x)
  (mapcar 'fbcheck (loop for i from 1 to x collect i)))
```
```cl
(fizzbuzz 100)
("1" "2" "Fizz" "4" "Buzz" "Fizz" "7" "8" "Fizz" "Buzz"...
```
かなり似ていますね[^4]。

[^4]: ただしやっぱりmapやseqなどをErlangの関数であるlists:map, lists:seqで呼び出さないといけなかったり、map関数で適用される関数をlambda式でくくらないといけなかったりややめんどくさい面が。

### Elixirと使い勝手を比べてみて

* Elixirには**iex**という超強力なREPLがあるが、LFEのREPL(lfe)はErlangのerlと同程度の使い勝手。特にiexのh/1コマンドにはお世話になっているのでああいうのがないと辛い。
* 同様にプロジェクト管理がErlangの**rebar**を「何とか使えるかな」という状態。
* 資料が少ない。本家サイトのドキュメントもあちこちが工事中。
* 当然ライブラリも少ない。というかはじめからErlangのライブラリを利用することしか考えていないかもしれない。

ということでどうも「Erlangの文法は大嫌いだけどErlang VMの機能は慣れてるLispで使いたい」という強い要望と意思を持った人でないと使っていけないかな…と思いました[^5]。

[^5]: しばらくLispいじってなかったんで復習にはなりました。

----
おまけ：
RaspbianにはCommon Lisp(glisp)はapt-getから入るんですね…