純粋関数型言語 Haskell を使ってみた

この記事は [Crowdworks Advent Calendar 2015](http://qiita.com/advent-calendar/2015/crowdworks) 16日目の記事になります．

こんにちは、どうでしょう藩士の[飯田](https://www.facebook.com/kosuke.iida)です。

DVD第24弾「ユーコン川160キロ～地獄の6日間～」が本日から予約が始まりました！
ユーコンは名脇役（女性現地ガイド熊谷さん）あり、名言ありなので今から楽しみです！！
ちなみに個人的には「ひとり不思議発見」が好きですｗ

# はじめに

前置きはこれくらいにして、本題に入ります。

`Scala`で関数型言語を初めて触り、関数型言語に興味を持ちました。

# 関数型言語とは？

ちなみに関数型言語とはどんな言語のことを言うのでしょうか？

関数型言語とは？（Wikipediaからの引用）
> 関数型言語（かんすうがたげんご、英: functional language）は、以下に述べる関数型プログラミングを基本スタイルとして推奨する機能を持つプログラミング言語、関数型プログラミング言語[1]の略称である。

つまり、関数型プログラミングとは？（Wikipediaからの引用）
> 何をもって関数型プログラミングとするか、関数型プログラミングを行っているコミュニティ内でも正確な定義や合意というものは存在しないが、一般的には、手続き型プログラミングがコマンド実行の列としてプログラムを記述していくのに対し、関数型プログラミングは複数の式を関数の適用によって組み合わせていくプログラミングスタイルである、ということは広く認められている。

と、いうことなんですね。

確かに`Scala`で実装するとき関数を組み合わせてコーディングしてました。
ここが手続き型プログラミングとの違いで、とっつきにくい部分かもしれないです。
関数型に慣れてくるとこの組み合わせる感覚がビシっとハマった時気持ちいいんですよねー

# メリットは？

あと、関数型言語のメリットです。（お約束的な）

* 第一級関数・高階関数
* 副作用がない

`副作用がない` ことによって、テストがしやすかったり、部分プログラム化しやすかったりなどの恩恵を受けることが出来ます。

# 代表的な関数型言語

そういえば、`Scala`以外にどんな関数型言語があるのでしょうか？
調べたら結構いろんな言語がありました、結構ね。

| 言語 | 純粋さ | 型付け |
|:--|:--|:--|
|Clean|純粋|強い、静的|
|Erlang|非純粋|動的|
|F#|非純粋|強い、静的|
|Haskell|純粋|強い、静的|
|Idris|純粋|強い、静的|
|Lazy K|純粋|型なし|
|LISP|非純粋|動的|
|Miranda|純粋|強い、静的|
|ML|非純粋|強い、静的|
|SML#|非純粋|強い、静的|
|Standard ML|非純粋|強い、静的|
|OCaml|非純粋|強い、静的|
|Scala|非純粋|強い、静的|
|Scheme|非純粋|動的|
|Unlambda|非純粋|型なし|
※[Wikipedia引用](https://ja.wikipedia.org/wiki/%E9%96%A2%E6%95%B0%E5%9E%8B%E8%A8%80%E8%AA%9E#.E4.BB.A3.E8.A1.A8.E7.9A.84.E3.81.AA.E9.96.A2.E6.95.B0.E5.9E.8B.E8.A8.80.E8.AA.9E)

# `非純粋`と`純粋`がある

また、関数型って`非純粋`、`純粋`の2パターンあるんですね！

`純粋`な関数型どんなのか気になる！
という単純な興味本位から今回、純粋関数型言語`Haskell`を触ってみました！

ちなみに、純粋関数型言語とは？(Wikipediaより引用)

> 純粋関数型言語では、参照透過性が常に保たれるという意味において、全ての式や関数の評価時に副作用を生まない。純粋関数型言語であるHaskellやCleanは非正格な評価を基本としており、引数はデフォルトで遅延評価される。一方、Idrisは純粋だが正格評価を採用している。入出力などを参照透過性を保ったまま実現するために、たとえば Haskell ではモナド、Clean では一意型（英語版）という特殊な型を通して一貫性のある表現を提供する。

つまり、`副作用が全くない`ない関数型言語ということです。
なるほど、確かに`Scala`は再代入できる(`var`など)ので`非純粋`とうことで納得です:smile:
* 変数定義の時に値を設定し、その後値を再代入できなければ副作用は起きない 

なぜ今回、純粋関数言語の中で`Haskell`を選んだかは、関数型言語で調べた時に`LISP`や`Haskell`がよく検索でひっかかり、その中で`静的型付け`が`Haskell`だったからです。

# Haskellのインストール

まずは`Haskell`が実行できるようにするため、Macにインストールしていきます。
※ Windowsはちょっとわかりません・・・

`brew` でサクッとインストールできるんですが、バージョンが古くなるということで
今回はパッケージからインストールします。

## ghc をイントールする
1. http://ghcformacosx.github.io/ からzipファイルをダウンロードして、インストールする
2. zipファイルを解凍し、実行ファイルを Applicationフォルダに移動します
3. ファイルを実行し`Append to ~/.bash_profile` をクリックし、`Modify` を選択する

以上でインストールは終わりです、簡単ですね！

## ghcが無事インストールされたか確認します
```bash
$ ghci
GHCi, version 7.10.2: http://www.haskell.org/ghc/  :? for help
Prelude> print "Hello World"
"Hello World"
Prelude>:quit
Leaving GHCi.
```

はい、お決まりの`Hello World`が出力されました。
めでたしめでたし。

# `Haskell`を使ってみた
## フィボナッチ数列
関数型言語は再帰が得意ということなので、フィボナッチ数列をやってみました（正確には調べました）。

```hs:fibonacci.hs
fibonacci = 1:1:zipWith (+) fibonacci (tail fibonacci)
```
ホント１行でかけるんですね、でもかなりキモいです。
※[このページ](http://shokos.hatenablog.com/entry/2012/12/08/015157)を参考にするとわかりやすいです。

そして、実行するとこんな感じ。

```bash
$ ghci
HCi, version 7.10.2: http://www.haskell.org/ghc/  :? for help
Prelude> :l fibonacci.hs
[1 of 1] Compiling Main             ( fibonacci.hs, interpreted )
Ok, modules loaded: Main.
*Main> fibonacci
[1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986,102334155,165580141,267914296,・・・
```
と、メモリを食い尽くすまで無限に実行されますｗ

ちなみにこれを`Java`で書くとこんな感じです。
`Haskell`と違いfor文を使い、再代入(`i++`や`a[i] = a[i-1] + a[i-2]`など)が発生してます。

```java:Fibonacci.java
import java.io.*;
  
public class Fibonacci
{
    public static void main(String[] args) throws Exception{
        int num = Integer.parseInt(args[0]);
  
        int[] a;
        a = new int [num];
        for(int i = 1; i < num; i++){
            if(i == 1){
                a[i] = 1;
            }
            else{
                a[i] = a[i-1] + a[i-2];
            }
            System.out.println(a[i]);
        }
    }
}
```

`Haskell`に比べるとはるかにコード量が多いですよね。

関数型は再起処理が書きやすいのが見て分かります。

ただ`フィボナッチ数列`だけでは、`非純粋` でも同じような恩恵を受けられるので、
まだ`純粋`のこんなところが良いというのは無いですね。

ちなみに`Scala`でも`Haskell`と同じく1行でかけます。
`Haskell`より`Scala`のが読みやすい（慣れの問題ですかね？）ので`Scala`で十分かなって感じです。

```scala
val fibonacchi: Stream[Int] = 1 #:: fibonacchi.scanLeft(1)(_ + _)
```

# 最後に
`純粋`は`非純粋`に比べて◯◯的なことを書こうと思ってたのですが、
`関数型言語`の話になってしまいました。。。すみません。

次回は`Haskell`で何かアプリを作って、こんな時`副作用`がなくてよかった、`副作用`が欲しかったなどを書こうかと思います。

# エンジニア絶賛募集中！

弊社では自らの技術で「21世紀の新しいワークスタイル」を実現したいエンジニア募集しています！
https://www.wantedly.com/projects/34041