プログラミング言語の学習は一般に大変である。
最初にどのようなことをすればいいのか、どの本をよむべきなのか等疑問は尽きない。マイナーな言語で情報が少なければなおさらである。
この記事では諸事情でHaskellに入門することになった方にむけて、どのように勉強していくか、参考にすべき本や記事を紹介する。
より良い指針にするためにも、指摘、感想等はコメントや私のTwitterアカウント(@Lugendre)に投稿して頂けるとありがたい。
入門〜初心者
環境構築
まずどんなプログラミング言語においても、プログラミングをする環境が必要である。Haskellにおいては Stackと呼ばれるツールをインストールすることによって、コンパイラ(GHC)、モジュールのインストール、ビルドなど自動でやってくれるようになるので、とりあえず脳死でStackをインストールしておけば良い。
以下の@igrepさんの記事が参考にすると良い。
Stackでやる最速Haskell Hello world! (GHCのインストール付き!)
他にもHaskell 教養としての関数型プログラミングや先日発売したHaskell入門にも詳しく書いてある。
Haskellには優れたIDEとして広く知られているものはない。どうしても優れたIDEで開発したいというのならば自分で作るしか無いのが現状である。よって現状の開発環境としては自分の好きなテキストエディタとStackで十分である。好きなテキストエディタが無いのであればAtomを利用するのが良いだろう。
また、Haskellらしいきれいなコードを意識するためにも stylish-haskell や hlint を使うことを強くおすすめする。
これらのツールはStackよりインストールできる。詳しくは@ncaqさんの以下の記事を参考されたし。
2017-10-07
Haskellを書くときはstylish-haskellとhlintを使って労せずして綺麗なコードを書きましょう
基本的な文法、考え方について知る
Haskell入門の鉄板本であるすごいHaskellたのしく学ぼう!(通称すごいH本)を読むのが良い。ネット上の下手なHaskell入門記事を読むよりもこれを読もう。お金がないのであれば、英語版を読むと良い。ここで注意すべきはすごいH本は環境構築のお話が若干古いので、参考にしないこと。
加えて、Haskell入門も必読である。名前に反し、すごいH本よりも若干高度な内容が扱われているが、Haskellを実践で扱うのに必要な内容が余すことなく書いてある。
Haskellにおける関数型プログラミングの考え方になれるためにも、手を動かしながら読むと良い。
わからないところがあれば後に紹介するHaskell-jpのSlackやTwitterで質問をすると初心者に飢えたHaskellerたちがこぞって教えてくれる。
モナドについて
度々話題になるモナドについてだが、基本的には具体的なモナド(StateやMaybe, IOなど)をただ使えるようになれば良い。数学の圏論の話などはまったく知らなくて良い。1すごいH本を読んで行けば具体的な使い方が出てくるので、一緒に手を動かしながら使い方を学ぶと良い。残念ながら すごいH本だけではモナドに関して十分な理解は得られない。 Haskell入門も同時に参照するとよい。
[演習]簡単なものを作ってみる
ここらまで来たらちょっとした演習としてパーサーコンビネータを作ってみよう。これは題材として非常に優秀で、基本的なモナドの使い方とその威力を体感することができる。Haskellによる関数プログラミングの思考法(IFPH)の11章やお気楽Haskellプログラミング入門やWHAT I WISH I KNEW WHEN LEARNING HASKELLを参考にすると良い。
ここまで来たら初心者卒業と言っても良いだろう。おめでとう!
脱初心者を目指す
実践的内容を知る
残念ながら、上記の内容だけではHaskellで実践的なプログラミングはできない。ここでは実践的なプログラミングに必要な幾つかの要素を紹介する。
複数のモナドを扱うのに必要な モナド変換子 はHaskell入門で詳しく紹介されている。@7shiさんのHaskell モナド変換子超入門も良いだろう。
また、Haskell入門は各モナドの使い分けや使用方法に関しても詳しく載っている。一度目を通しておくべきだ。
また、標準ライブラリやよく使うライブラリ、フレームワークについても知っておくべきだろう。これに関してもHaskell入門によくまとめられている。
特に Lens/PrismはHaskellで複雑なデータ構造を扱う上で欠かせない。Haskell入門でも紹介されているが、Lensの最低限の使い方のみであるがこの段階ではそれで十分だろう。
他にもテストはdoctest, QuickCheck, Hspec, HUnitがある。テストフレームワークとしてはtest-frameworkがある。QuickCheckは関数プログラミングの楽しみや関数プログラミング実践入門で、doctestは関数プログラミング実践入門で, HUnitはHaskell入門で取り上げられている。test-frameworkやHspecなどはライブラリのドキュメントを見ると良いだろう。
遅延評価 はプログラミングのパフォーマンスに直結する。適度に正格評価をしてやる必要があるが、当然デメリットも有る。GHCと遅延評価の話題に関してはHaskellによる関数プログラミングの思考法(IFPH)やGHCの公式ドキュメント、反駁不可パターンなどはWHAT I WISH I KNEW WHEN LEARNING HASKELLを参照すると良い。
[演習]Webアプリケーションを作ってみる
ここまでの知識を用いて実践的なプログラミングとして、Webアプリケーションを作ってみるのは良い練習になる。Haskell入門では最後にWebアプリケーションを作っているので、一緒に作っているのが良いだろう。関数プログラミングの基礎的な考え方も身につく。
ここまでできれば中級者だ。実践的なプログラミングも十分に可能だろう。
並列・並行プログラミング
Haskellは並列・並行プログラミングが得意であると言われている。
これらに関してはHaskell入門、Haskellによる並列・並行プログラミングを参照すると良い。
更に深く(おまけ)
Haskellを極めたい、更に深く知りたいという方に対する指針。
データ構造とアルゴリズム
関数型言語には関数型言語のデータ構造とアルゴリズムがある。純粋関数型データ構造2や関数プログラミング 珠玉のアルゴリズムデザインを読むと良い。
関数プログラミングの考え方を学ぶ
関数プログラミングの楽しみはHaskellによる関数プログラミングの事例が多く載っている。また、Haskellのテスト方法やArrowと言った非常に便利な型クラスの使い方も詳しく載っている。Haskellerならぜひ一度読んでおくべきである。
練習問題も豊富なので、腕試しとしても使える。
GHC拡張について
GHC拡張とは, Haskellの言語仕様にはない機能を提供するGHCの言語拡張である。ほぼ必須なものから使い所がわからないものまで多種多様である。それぞれの使用方法とモチベーションはGHCの公式ドキュメントやWHAT I WISH I KNEW WHEN LEARNING HASKELLに書いてある。よく使う、話題に上がる拡張については別記事で紹介、または追記する。3
型システムと意味論
関数プログラミング(特にHaskell)は意味論や型システムと密接な関わりがある。またいくつかのよく使われるGHC拡張には型システムの知識を要求するものがある。これらを知っておくことはHaskellだけでなく他のプログラミングに於いても有用だろう。型システムや操作的意味論、λ計算の基本は型システム入門で、カテゴリ理論を含む各種意味論はプログラム意味論で学ぶことができる。
Hindley-Milner型システムに関しては知っておく必要があるだろう。
[演習]型で遊ぶ
これらで学んだ部分型や全称型、存在型、依存型、高階多相などはGHC拡張などを用いてすぐに試すことができる。
Haskellで試しながら読み進めていくと良い。WHAT I WISH I KNEW WHEN LEARNING HASKELLでは型システム入門よりも発展的な話題についても紹介されている。
HaskellとGHC拡張による型レベルプログラミングの記事を探しても良いだろう。
圏論
Haskellと圏論の関わりは深い。Hackageなどのライブラリの説明に平然と圏論の用語が出てくることも多い。圏論については圏論 原著や圏論の基礎を読むと良い。併せて圏論.hsのスライドや動画を参照するとHaskellとの関連性がわかる。
HaskellでもCategoryとかArrowとかProfunctorとかBifunctorとか山ほどある。WHAT I WISH I KNEW WHEN LEARNING HASKELLを参照されたし。4
[演習]圏論が背景にあるライブラリを作って遊ぶ
有用性や新規性はおいておいて、圏論にある概念をHaskellで書くことができるかチャレンジしてみると良い。
Lens/Prism
Lens/Prismに関して更に詳しい情報が知りたければ@igrepさんのLens&Prism勉強会 私的まとめに様々な記事、スライドが紹介されている。他にはソースコードを読むくらいしか……5
もっとモナド
(Haskellにおける)モナドをちゃんと知りたいならば、関数プログラミングの楽しみのArrowの章を読んだり、Notions of computation and monadsを読むと良い。@hiruberutoさんのモナドはポケモン。数学が出てこないモナド入門も参考になる。
FreeモナドやOperationalモナドを使えると便利である。@fumievalさんのFreeモナドを超えた!?operationalモナドを使ってみようで説明されている。
他にもMonad Morphismについて知るのも有用だ。Control.Monad.MMorphや@hirataraさんのモナドモナド (LT没ネタ)を参照すると良い。
[演習]モナドを作る
この計算ってモナドとして抽象化できるのではと感じたら積極的に試してみよう。
過去に書いたコードをリファクタリングするのも勉強になる。
Extensible Effect
モナド変換子は合成するモナドの数が多いほど効率が悪くなるなどの問題点がある。そこで、モナドではなくEffect Systemを用いた計算の表現を使う方法もある。詳しくはExtensible Effects はモナド変換子に対する救世主になり得るか?を参照されたし。
Effect systemについて知りたければType and Effect systemという論文を読むと良い。
[演習]モナド変換子をExtensible Effectに置き換える
今まで書いたコードのモナド変換子をExtensible Effectに置き換えてみよう。
ArrowとArrow記法
関数プログラミングにおいては、関数のような小さな計算の集まりを合成してプログラムを作るという考え方がある。これを強力にサポートするものとしてArrow型クラスとGHC拡張のArrowsがある。これはGUIのような反応状況モデルと相性が良い。これに関してはGHCの公式ドキュメントと関数プログラミングの楽しみを読むと良い。
融合変換
一般に効率と可読性、保守し易さはトレードオフの関係にある。我々としては可読性が高く、保守しやすいコードを自動で効率のよいコードに変換してほしい。こういった際に融合変換による最適化は有用である。詳しくは関数プログラミングの楽しみを読むと良い。
FFI
HaskellではC言語の関数を呼び出すことができる。型安全性が保たれるのかとかなどは私もあまり良くわかっていない。WHAT I WISH I KNEW WHEN LEARNING HASKELLに一応書いてある。
unsafeHaskell
GHC拡張などの中にはHaskellの型システムを破壊しうる関数があり、そういった関数はunsafeという接頭辞が付いている。基本的にこれらを使うと深い悲しみに包まれることになるので使わない方が良い。SafeHaskell拡張を使えばこれらを抑制できる。6
Haskellでオブジェクト指向プログラミングしたい!
基本的にHaskellでOOPをする必要性はないのだが、ゲームの制作などの限られた領域ではOOPは便利である。HaskellでOOPをするにあたってobjectiveというライブラリを使うと良い。@its_out_of_tuneさんのHaskellオブジェクト指向に触れてみよう〜初級編〜や生みの親の@fumievalさんのHaskellでの合成可能なオブジェクトの構成とその応用を参考すると良い。他にも純粋関数型オブジェクト指向7に関しては型システム入門でテーマとして取り扱っている。
その他
LiquidHaskell8を使った静的コード解析や定理証明やらも有用。形式手法については知っていたほうが良いだろう。9 圏論データベースの話も面白い。
ここまで来たら後は様々なコードを読んでイディオムを学んでいくと良い。
[演習]Elmコンパイラを読む
これらの知識があればElmのコンパイラのソースコードを読むことが可能だろう。Elmのコンパイラで肩慣らしをしてからGHCのソースコードを読んでみてもよい。ElmやHaskellの言語仕様のみのインタプリタを実装しても良い。
今すぐ参加すべきコミュニティ
Haskell-jpという日本のHaskellerの集まりがある。逆引き辞典や査読付きなので信頼性の高いHaskellの記事がある。誰でも参加できるSlackチームもあり、無限にHaskellの情報が流れてくるは、強いHaskellerたちに質問できるので今すぐ参加しよう!
Haskellもくもく会
Haskell-jp主催でHaskellのもくもく会が毎月開催されている。
初心者も歓迎されるので奮ってご参加を!
困ったときには
- ググってみる。
- WHAT I WISH I KNEW WHEN LEARNING HASKELLに書いてないか確認する。10
- Haskell-jpのSlackで聞いてみる。11
TwitterでHaskellerをフォローして仲良くなると困ったときに助けてくれる。
アドバイス
- すごいH本やHaskell入門は何回も読み返す。
- エラーメッセージは友と思う。めげない。
- 英語を忌避しない。
- 日本語でググってないときは英語でググるとすぐ出てくる。
- わからないことはすぐ質問する。
- 論文を忌避しない。12
- 演算子や関数がなにかわからないときはHoogleやHayoo!で検索してみる。13
- 圏論の基礎とか型システム入門は辞書的な使い方でも有用なので買っとけ14
結論
すごいH本とHaskell入門を買って手を動かしながら読み、わからないところをHaskell-jpのSlackで質問すれば中級者にはなれる。
この記事で出てきた本, 記事の一覧
- Stackでやる最速Haskell Hello world! (GHCのインストール付き!)
- Haskell 教養としての関数型プログラミング
- Haskell入門
- 2017-10-07
Haskellを書くときはstylish-haskellとhlintを使って労せずして綺麗なコードを書きましょう - すごいHaskellたのしく学ぼう!
- Haskellによる関数プログラミングの思考法
- お気楽Haskellプログラミング入門
- WHAT I WISH I KNEW WHEN LEARNING HASKELL
- Haskellによる並列・並行プログラミング
- Haskell モナド変換子超入門
- 関数プログラミング実践入門
- 純粋関数型データ構造
- 関数プログラミング 珠玉のアルゴリズムデザイン
- モナドはポケモン。数学が出てこないモナド入門
- Freeモナドを超えた!?operationalモナドを使ってみよう
- Control.Monad.MMorph
- モナドモナド (LT没ネタ)
- Extensible Effects はモナド変換子に対する救世主になり得るか?
- Type and Effect system
- 型システム入門
- プログラム意味論
- Lens&Prism勉強会 私的まとめ
- 圏論 原著
- 圏論の基礎
- 圏論.hs
- Haskellオブジェクト指向に触れてみよう〜初級編〜
- Haskellでの合成可能なオブジェクトの構成とその応用
- 入門LiquidHaskell−篩型による静的コード解析−
- Haskell-jp
-
私はいずれは知るべきだと考えているが、すくなくともこの段階で知るべきことではない。 ↩
-
残念ながらHaskellで書かれていない. ↩
-
多分紹介する。多分 ↩
-
困ったことに書きかけだが。 ↩
-
圏論による形式化の論文があった気がするのだが見つからない。 ↩
-
困ったことにTemplate Haskellも使えなくなる。 ↩
-
Haskell++とかO'Haskellとかもあるけども…… ↩
-
入門LiquidHaskell−篩型による静的コード解析−はLiquidHaskellに関する唯一(?)の本。 ↩
-
ここらへんに関しては目下勉強中なもんで。 ↩
-
強そうな質問で溢れており気後れするのも分かるが、初心者の質問も大歓迎される。 ↩
-
そこらのネットの記事の100億倍わかりやすいのが論文である。型システム入門を読んでおけばまず理解できるはずだ。 ↩
-
hgrksという言葉があるとかないとか。Hayoo!の方はほとんどすべてのパッケージが検索できるとか。 ↩
-
正直とりあえずで買える値段ではない。 ↩