Haskellの入門から中級者になるまでの指針

プログラミング言語の学習は一般に大変である。
最初にどのようなことをすればいいのか、どの本をよむべきなのか等疑問は尽きない。マイナーな言語で情報が少なければなおさらである。
この記事では諸事情でHaskellに入門することになった方にむけて、どのように勉強していくか、参考にすべき本や記事を紹介する。
より良い指針にするためにも、指摘、感想等はコメントや私のTwitterアカウント(@Lugendre)に投稿して頂けるとありがたい。

# 入門〜初心者
## 環境構築

まずどんなプログラミング言語においても、プログラミングをする環境が必要である。Haskellにおいては **Stack**と呼ばれるツールをインストールすることによって、コンパイラ(GHC)、モジュールのインストール、ビルドなど自動でやってくれるようになるので、とりあえず脳死でStackをインストールしておけば良い。
以下の@igrepさんの記事が参考にすると良い。
[Stackでやる最速Haskell Hello world! (GHCのインストール付き！)](https://qiita.com/igrep/items/da1d8df6d40eb001a561)

他にも[Haskell 教養としての関数型プログラミング](http://amzn.asia/cjNcHXP)や先日発売した[Haskell入門](http://amzn.asia/dZIoGJ7)にも詳しく書いてある。

Haskellには優れたIDEとして広く知られているものはない。どうしても優れたIDEで開発したいというのならば自分で作るしか無いのが現状である。よって現状の開発環境としては自分の好きなテキストエディタとStackで十分である。好きなテキストエディタが無いのであればAtomを利用するのが良いだろう。

また、Haskellらしいきれいなコードを意識するためにも **stylish-haskell** や **hlint** を使うことを強くおすすめする。
これらのツールはStackよりインストールできる。詳しくは@ncaqさんの以下の記事を参考されたし。
[2017-10-07
Haskellを書くときはstylish-haskellとhlintを使って労せずして綺麗なコードを書きましょう](https://www.ncaq.net/2017/10/07/)

## 基本的な文法、考え方について知る
Haskell入門の鉄板本である[すごいHaskellたのしく学ぼう！](http://amzn.asia/2RhgBDl)(通称すごいH本)を読むのが良い。ネット上の下手なHaskell入門記事を読むよりもこれを読もう。お金がないのであれば、[英語版](http://learnyouahaskell.com/chapters)を読むと良い。ここで注意すべきはすごいH本は環境構築のお話が若干古いので、参考にしないこと。
加えて、[Haskell入門](http://amzn.asia/dZIoGJ7)も必読である。名前に反し、すごいH本よりも若干高度な内容が扱われているが、Haskellを実践で扱うのに必要な内容が余すことなく書いてある。
Haskellにおける関数型プログラミングの考え方になれるためにも、手を動かしながら読むと良い。
わからないところがあれば後に紹介するHaskell-jpのSlackやTwitterで質問をすると初心者に飢えたHaskellerたちがこぞって教えてくれる。

## モナドについて
度々話題になるモナドについてだが、基本的には具体的なモナド(StateやMaybe, IOなど)をただ使えるようになれば良い。数学の圏論の話などはまったく知らなくて良い。[^1]すごいH本を読んで行けば具体的な使い方が出てくるので、一緒に手を動かしながら使い方を学ぶと良い。残念ながら **すごいH本だけではモナドに関して十分な理解は得られない。** [Haskell入門](http://amzn.asia/dZIoGJ7)も同時に参照するとよい。

[^1]: 私はいずれは知るべきだと考えているが、すくなくともこの段階で知るべきことではない。

## [演習]簡単なものを作ってみる
ここらまで来たらちょっとした演習としてパーサーコンビネータを作ってみよう。これは題材として非常に優秀で、基本的なモナドの使い方とその威力を体感することができる。[Haskellによる関数プログラミングの思考法](http://amzn.asia/d4uxed3)(IFPH)の11章や[お気楽Haskellプログラミング入門](http://www.geocities.jp/m_hiroi/func/haskell32.html)や[WHAT I WISH I KNEW WHEN LEARNING HASKELL](http://dev.stephendiehl.com/hask/)を参考にすると良い。

ここまで来たら初心者卒業と言っても良いだろう。おめでとう！

# 脱初心者を目指す
## 実践的内容を知る
残念ながら、上記の内容だけではHaskellで実践的なプログラミングはできない。ここでは実践的なプログラミングに必要な幾つかの要素を紹介する。

複数のモナドを扱うのに必要な **モナド変換子** は[Haskell入門](http://amzn.asia/dZIoGJ7)で詳しく紹介されている。@7shiさんの[Haskell モナド変換子超入門](https://qiita.com/7shi/items/4408b76624067c17e933)も良いだろう。
また、[Haskell入門](http://amzn.asia/dZIoGJ7)は各モナドの使い分けや使用方法に関しても詳しく載っている。一度目を通しておくべきだ。

また、標準ライブラリやよく使うライブラリ、フレームワークについても知っておくべきだろう。これに関しても[Haskell入門](http://amzn.asia/dZIoGJ7)によくまとめられている。
特に **Lens/Prism**はHaskellで複雑なデータ構造を扱う上で欠かせない。[Haskell入門](http://amzn.asia/dZIoGJ7)でも紹介されているが、Lensの最低限の使い方のみであるがこの段階ではそれで十分だろう。
他にもテストは**doctest**, **QuickCheck**, **Hspec**, **HUnit**がある。テストフレームワークとしては**test-framework**がある。QuickCheckは[関数プログラミングの楽しみ](http://amzn.asia/0viF1bE)や[関数プログラミング実践入門](http://amzn.asia/fMnNyyE)で、doctestは[関数プログラミング実践入門](http://amzn.asia/fMnNyyE)で, HUnitは[Haskell入門](http://amzn.asia/dZIoGJ7)で取り上げられている。test-frameworkやHspecなどはライブラリのドキュメントを見ると良いだろう。

**遅延評価** はプログラミングのパフォーマンスに直結する。適度に正格評価をしてやる必要があるが、当然デメリットも有る。GHCと遅延評価の話題に関しては[Haskellによる関数プログラミングの思考法](http://amzn.asia/d4uxed3)(IFPH)やGHCの公式ドキュメント、反駁不可パターンなどは[WHAT I WISH I KNEW WHEN LEARNING HASKELL](http://dev.stephendiehl.com/hask/)を参照すると良い。

## [演習]Webアプリケーションを作ってみる
ここまでの知識を用いて実践的なプログラミングとして、Webアプリケーションを作ってみるのは良い練習になる。[Haskell入門](http://amzn.asia/dZIoGJ7)では最後にWebアプリケーションを作っているので、一緒に作っているのが良いだろう。関数プログラミングの基礎的な考え方も身につく。

ここまでできれば中級者だ。実践的なプログラミングも十分に可能だろう。

## 並列・並行プログラミング
Haskellは並列・並行プログラミングが得意であると言われている。
これらに関しては[Haskell入門](http://amzn.asia/dZIoGJ7)、[Haskellによる並列・並行プログラミング](http://amzn.asia/3VgbyYr)を参照すると良い。

# 更に深く(おまけ)
Haskellを極めたい、更に深く知りたいという方に対する指針。

## データ構造とアルゴリズム
関数型言語には関数型言語のデータ構造とアルゴリズムがある。[純粋関数型データ構造](http://amzn.asia/hFHLLoy)[^2]や[関数プログラミング 珠玉のアルゴリズムデザイン](http://amzn.asia/6N5w9B5)を読むと良い。

[^2]: 残念ながらHaskellで書かれていない.

## 関数プログラミングの考え方を学ぶ
[関数プログラミングの楽しみ](http://amzn.asia/0viF1bE)はHaskellによる関数プログラミングの事例が多く載っている。また、Haskellのテスト方法やArrowと言った非常に便利な型クラスの使い方も詳しく載っている。Haskellerならぜひ一度読んでおくべきである。
練習問題も豊富なので、腕試しとしても使える。

## GHC拡張について
GHC拡張とは, Haskellの言語仕様にはない機能を提供するGHCの言語拡張である。ほぼ必須なものから使い所がわからないものまで多種多様である。それぞれの使用方法とモチベーションはGHCの公式ドキュメントや[WHAT I WISH I KNEW WHEN LEARNING HASKELL](http://dev.stephendiehl.com/hask/)に書いてある。よく使う、話題に上がる拡張については別記事で紹介、または追記する。[^3]

[^3]: 多分紹介する。多分

## 型システムと意味論
関数プログラミング(特にHaskell)は意味論や型システムと密接な関わりがある。またいくつかのよく使われるGHC拡張には型システムの知識を要求するものがある。これらを知っておくことはHaskellだけでなく他のプログラミングに於いても有用だろう。型システムや操作的意味論、λ計算の基本は[型システム入門](http://amzn.asia/6Q1Gd9x)で、カテゴリ理論を含む各種意味論は[プログラム意味論](http://amzn.asia/dbMhj4K)で学ぶことができる。
Hindley-Milner型システムに関しては知っておく必要があるだろう。

### [演習]型で遊ぶ
これらで学んだ部分型や全称型、存在型、依存型、高階多相などはGHC拡張などを用いてすぐに試すことができる。
Haskellで試しながら読み進めていくと良い。[WHAT I WISH I KNEW WHEN LEARNING HASKELL](http://dev.stephendiehl.com/hask/)では型システム入門よりも発展的な話題についても紹介されている。
HaskellとGHC拡張による型レベルプログラミングの記事を探しても良いだろう。

## 圏論
Haskellと圏論の関わりは深い。Hackageなどのライブラリの説明に平然と圏論の用語が出てくることも多い。圏論については[圏論 原著](http://amzn.asia/hmEqpbh)や[圏論の基礎](http://amzn.asia/0tPSJci)を読むと良い。併せて[圏論.hs](https://sites.google.com/site/klovelab/Home/category)のスライドや動画を参照するとHaskellとの関連性がわかる。
HaskellでもCategoryとかArrowとかProfunctorとかBifunctorとか山ほどある。[WHAT I WISH I KNEW WHEN LEARNING HASKELL](http://dev.stephendiehl.com/hask/)を参照されたし。[^4]

### [演習]圏論が背景にあるライブラリを作って遊ぶ
有用性や新規性はおいておいて、圏論にある概念をHaskellで書くことができるかチャレンジしてみると良い。

[^4]: 困ったことに書きかけだが。

## Lens/Prism
Lens/Prismに関して更に詳しい情報が知りたければ@igrepさんの[Lens&Prism勉強会 私的まとめ](http://the.igreque.info/posts/2015-06-09-lens-prism.html)に様々な記事、スライドが紹介されている。他にはソースコードを読むくらいしか……[^5]

[^5]: 圏論による形式化の論文があった気がするのだが見つからない。

## もっとモナド
(Haskellにおける)モナドをちゃんと知りたいならば、[関数プログラミングの楽しみ](http://amzn.asia/0viF1bE)のArrowの章を読んだり、[Notions of computation and monads](http://www.cs.cmu.edu/~crary/819-f09/Moggi91.pdf)を読むと良い。@hiruberutoさんの[モナドはポケモン。数学が出てこないモナド入門](https://qiita.com/hiruberuto/items/8bbc0343bf794c368287)も参考になる。
FreeモナドやOperationalモナドを使えると便利である。@fumievalさんの[Freeモナドを超えた!?operationalモナドを使ってみよう](http://fumieval.hatenablog.com/entry/2013/05/09/223604#f2)で説明されている。

他にもMonad Morphismについて知るのも有用だ。[Control.Monad.MMorph](https://hackage.haskell.org/package/mmorph-1.1.0/docs/Control-Monad-Morph.html)や@hirataraさんの[モナドモナド (LT没ネタ)](https://qiita.com/hiratara/items/65fcf38070def7e5a918)を参照すると良い。

### [演習]モナドを作る
この計算ってモナドとして抽象化できるのではと感じたら積極的に試してみよう。
過去に書いたコードをリファクタリングするのも勉強になる。

## Extensible Effect
モナド変換子は合成するモナドの数が多いほど効率が悪くなるなどの問題点がある。そこで、モナドではなくEffect Systemを用いた計算の表現を使う方法もある。詳しくは[Extensible Effects はモナド変換子に対する救世主になり得るか?](http://konn-san.com/prog/haskell/extensible-effects.html)を参照されたし。
Effect systemについて知りたければ[Type and Effect system](http://web.cs.ucla.edu/~palsberg/tba/papers/nielson-nielson-csd99.pdf)という論文を読むと良い。

### [演習]モナド変換子をExtensible Effectに置き換える
今まで書いたコードのモナド変換子をExtensible Effectに置き換えてみよう。

## ArrowとArrow記法
関数プログラミングにおいては、関数のような小さな計算の集まりを合成してプログラムを作るという考え方がある。これを強力にサポートするものとしてArrow型クラスとGHC拡張のArrowsがある。これはGUIのような反応状況モデルと相性が良い。これに関してはGHCの公式ドキュメントと[関数プログラミングの楽しみ](http://amzn.asia/0viF1bE)を読むと良い。

## 融合変換
一般に効率と可読性、保守し易さはトレードオフの関係にある。我々としては可読性が高く、保守しやすいコードを自動で効率のよいコードに変換してほしい。こういった際に融合変換による最適化は有用である。詳しくは[関数プログラミングの楽しみ](http://amzn.asia/0viF1bE)を読むと良い。

## FFI
HaskellではC言語の関数を呼び出すことができる。型安全性が保たれるのかとかなどは私もあまり良くわかっていない。[WHAT I WISH I KNEW WHEN LEARNING HASKELL](http://dev.stephendiehl.com/hask/)に一応書いてある。

## unsafeHaskell
GHC拡張などの中にはHaskellの型システムを破壊しうる関数があり、そういった関数はunsafeという接頭辞が付いている。基本的にこれらを使うと深い悲しみに包まれることになるので使わない方が良い。SafeHaskell拡張を使えばこれらを抑制できる。[^6]

[^6]: 困ったことにTemplate Haskellも使えなくなる。

## Haskellでオブジェクト指向プログラミングしたい！
基本的にHaskellでOOPをする必要性はないのだが、ゲームの制作などの限られた領域ではOOPは便利である。HaskellでOOPをするにあたって**objective**というライブラリを使うと良い。@its_out_of_tuneさんの[Haskellオブジェクト指向に触れてみよう〜初級編〜](http://tune.hateblo.jp/entry/2015/03/27/035648)や生みの親の@fumievalさんの[Haskellでの合成可能なオブジェクトの構成とその応用](https://fumieval.github.io/papers/ja/2015-Haskell-objects.pdf)を参考すると良い。他にも純粋関数型オブジェクト指向[^7]に関しては[型システム入門](http://amzn.asia/6Q1Gd9x)でテーマとして取り扱っている。

[^7]: Haskell++とかO'Haskellとかもあるけども……

## その他
LiquidHaskell[^8]を使った静的コード解析や定理証明やらも有用。形式手法については知っていたほうが良いだろう。[^9] 圏論データベースの話も面白い。

ここまで来たら後は様々なコードを読んでイディオムを学んでいくと良い。

[^8]: [入門LiquidHaskell−篩型による静的コード解析−](https://dodgsonlabs.booth.pm/items/490689)はLiquidHaskellに関する唯一(?)の本。
[^9]: ここらへんに関しては目下勉強中なもんで。

### [演習]Elmコンパイラを読む
これらの知識があればElmのコンパイラのソースコードを読むことが可能だろう。Elmのコンパイラで肩慣らしをしてからGHCのソースコードを読んでみてもよい。ElmやHaskellの言語仕様のみのインタプリタを実装しても良い。

# 今すぐ参加すべきコミュニティ
[Haskell-jp](https://haskell.jp/)という日本のHaskellerの集まりがある。逆引き辞典や査読付きなので信頼性の高いHaskellの記事がある。誰でも参加できるSlackチームもあり、無限にHaskellの情報が流れてくるは、強いHaskellerたちに質問できるので今すぐ参加しよう！

## Haskellもくもく会
Haskell-jp主催で[Haskellのもくもく会](https://haskellmokumoku.connpass.com/)が毎月開催されている。
初心者も歓迎されるので奮ってご参加を！

# 困ったときには
1. ググってみる。
2. [WHAT I WISH I KNEW WHEN LEARNING HASKELL](http://dev.stephendiehl.com/hask/)に書いてないか確認する。[^10]
3. Haskell-jpのSlackで聞いてみる。[^11]

TwitterでHaskellerをフォローして仲良くなると困ったときに助けてくれる。

[^10]: 一応[日本語版](https://github.com/shiatsumat/wiwinwlh-jp/wiki)もあるが古い上に不完全である。
[^11]: 強そうな質問で溢れており気後れするのも分かるが、初心者の質問も大歓迎される。

# アドバイス
1. すごいH本やHaskell入門は何回も読み返す。
2. エラーメッセージは友と思う。めげない。
3. 英語を忌避しない。
4. 日本語でググってないときは英語でググるとすぐ出てくる。
5. わからないことはすぐ質問する。
6. 論文を忌避しない。[^12]
7. 演算子や関数がなにかわからないときはHoogleやHayoo!で検索してみる。[^13]
8. 圏論の基礎とか型システム入門は辞書的な使い方でも有用なので買っとけ[^14]

[^12]: そこらのネットの記事の100億倍わかりやすいのが論文である。型システム入門を読んでおけばまず理解できるはずだ。
[^13]: hgrksという言葉があるとかないとか。Hayoo!の方はほとんどすべてのパッケージが検索できるとか。
[^14]: 正直とりあえずで買える値段ではない。

# 結論

すごいH本とHaskell入門を買って手を動かしながら読み、わからないところをHaskell-jpのSlackで質問すれば中級者にはなれる。

# この記事で出てきた本, 記事の一覧
* [Stackでやる最速Haskell Hello world! (GHCのインストール付き！)](https://qiita.com/igrep/items/da1d8df6d40eb001a561)
* [Haskell 教養としての関数型プログラミング](http://amzn.asia/cjNcHXP)
* [Haskell入門](http://amzn.asia/dZIoGJ7)
* [2017-10-07
Haskellを書くときはstylish-haskellとhlintを使って労せずして綺麗なコードを書きましょう](https://www.ncaq.net/2017/10/07/)
* [すごいHaskellたのしく学ぼう！](http://amzn.asia/2RhgBDl)
* [Haskellによる関数プログラミングの思考法](http://amzn.asia/d4uxed3)
* [お気楽Haskellプログラミング入門](http://www.geocities.jp/m_hiroi/func/haskell32.html)
* [WHAT I WISH I KNEW WHEN LEARNING HASKELL](http://dev.stephendiehl.com/hask/)
* [Haskellによる並列・並行プログラミング](http://amzn.asia/3VgbyYr)
* [Haskell モナド変換子超入門](https://qiita.com/7shi/items/4408b76624067c17e933)
* [関数プログラミング実践入門](http://amzn.asia/fMnNyyE)
* [純粋関数型データ構造](http://amzn.asia/hFHLLoy)
* [関数プログラミング 珠玉のアルゴリズムデザイン](http://amzn.asia/6N5w9B5)
* [モナドはポケモン。数学が出てこないモナド入門](https://qiita.com/hiruberuto/items/8bbc0343bf794c368287)
* [Freeモナドを超えた!?operationalモナドを使ってみよう](http://fumieval.hatenablog.com/entry/2013/05/09/223604#f2)
* [Control.Monad.MMorph](https://hackage.haskell.org/package/mmorph-1.1.0/docs/Control-Monad-Morph.html)
* [モナドモナド (LT没ネタ)](https://qiita.com/hiratara/items/65fcf38070def7e5a918)
* [Extensible Effects はモナド変換子に対する救世主になり得るか?](http://konn-san.com/prog/haskell/extensible-effects.html)
* [Type and Effect system](http://web.cs.ucla.edu/~palsberg/tba/papers/nielson-nielson-csd99.pdf)
* [型システム入門](http://amzn.asia/6Q1Gd9x)
* [プログラム意味論](http://amzn.asia/dbMhj4K)
* [Lens&Prism勉強会 私的まとめ](http://the.igreque.info/posts/2015-06-09-lens-prism.html)
* [圏論 原著](http://amzn.asia/hmEqpbh)
* [圏論の基礎](http://amzn.asia/0tPSJci)
* [圏論.hs](https://sites.google.com/site/klovelab/Home/category)
* [Haskellオブジェクト指向に触れてみよう〜初級編〜](http://tune.hateblo.jp/entry/2015/03/27/035648)
* [Haskellでの合成可能なオブジェクトの構成とその応用](https://fumieval.github.io/papers/ja/2015-Haskell-objects.pdf)
* [入門LiquidHaskell−篩型による静的コード解析−](https://dodgsonlabs.booth.pm/items/490689)
* [Haskell-jp](https://haskell.jp/)