Haskellの学習のコツ?

まだHaskell初心者でLearn You a Haskell for Great Goodをちょくちょく読んだりしている。実際にアプリなどを作るまでは至っていないのだが、少しずつ全体的な感覚はつかめてきた。

関数の定義の仕方、パターンマッチの意味と使い方を理解する

昔初めてHaskellにトライしたときはここで早速つまずいた。関数定義において、関数の引数にa,bといった一般的な引数(小文字で始まる)あるいはデータコンストラクタ(大文字で始まる)を置くことができる。関数定義の左辺のデータコンストラクタは括弧でくくる。リストでのパターンマッチというのは「:」が記号のため初心者は少し混乱するかも。Treeとかの例のほうがわかりやすい。一回分かれば些細な違いなのだが。

data定義の意味

data Hoge a = Hoge a

=の左辺は型コンストラクタ、右辺はデータコンストラクタ。データコンストラクタはパターンマッチに使うことができる以外は、一般の関数と同じように(カリー化など)使え、名前に記号を使うことも出来る。データコンストラクタの意味は、パターンマッチで使うときになって初めて明確になる。昔学んだときは、データコンストラクタの実体は何?とか、データコンストラクタを呼ぶと何が起きるの?みたいな事を考えて混乱してしまった記憶がある。

再帰やfoldlなどを使った関数型特有の計算方法に慣れ親しむ。

リストは先頭要素と残りのリストを引数に持つデータコンストラクタ「:」で出来ていて、パターンマッチを使って再帰的にたどれる。ライブラリの中のData.Listモジュールにリスト上で計算する一連の関数がある。階乗の再帰など、ループを再帰に変換する際は、ループのカウンタがなくなる分、それが再帰関数の引数として追加される。foldやscan系の関数はEuler projectの解答集などを見ると、初心者にはなかなか思いつかない便利な使い方ができるようである。

IOを使うのにモナドの理解は必要ない。ひとまず仕組み自体はブラックボックスに入れておいて、<-とreturnの型と使い方を理解する。

モナドは計算をカプセル化する仕組み。カプセル化するため、中に文脈を持たせられる。IOモナドは特別なモナドで、カプセル化した中身の取り出しに制限がある(IOモナド内でのみ取り出し可能)。また、IOモナド内の関数は処理系によって逐次実行される。

型クラスはJavaでいうインターフェイス

型クラスは、型に対してある一連の関数が使えることを示すための仕組み。ただし型シグネチャのみでなく実装も含められる。それと、既存の型に対して後から自分の望む型クラスを追加可能。オブジェクト指向と違い、関数が型に所属するわけではないので、ある型に対して適用可能な新しい関数を型定義とは別にinstance宣言内で定義できる。上手く表現できないが、とりあえず型クラスは非常にパワフルな機能だとのことである。

型クラスについてのSimon Peyton Jonesによる言及(pdfの58〜62ページ)
http://conferences.oreillynet.com/presentations/os2007/os_peytonjones.pdf

型クラスのインスタンスを定義するとき、たとえばEqクラスの定義は

class Eq a where  
    (==) :: a -> a -> Bool ---以下略

なので、aには具象型が必要。
つまり、

instance (Eq m) => Eq (Maybe m) where

などと定義する。
一方でFunctorクラスの定義は

class Functor f where  
    fmap :: (a -> b) -> f a -> f b  

なのでfは引数が一つの型コンストラクタでなければならない。
つまり、

instance Functor Maybe where

instance Functor (Either a) where

などと定義する。

型クラスを理解した上で、Functor → Monadと学んでいく。

Monadは型クラスとして定義されている。そしてそのインスタンスは、Monadクラスの関数が3つのモナド則を満たすべく定義される。

Haskellにおいてモナドばかりが難しいと言われるが、モナドに関しては以下のレベルの理解でさしあたりは不便はないのでは、と思う。

Haskell Day2012 - 参照透過性とは何だったのか(34〜51ページ)←イメージをつかみやすい
http://www.slideshare.net/RuiccRail/haskell-day2012/34
モナドはメタファーではない(Scalaを使った説明)
http://eed3si9n.com/ja/monads-are-not-metaphors

まとめ

モナド自体よりは、今まで手続き型で書いていたアルゴリズムをどうやって関数型でスマートに書くかというイディオムを学ぶのに結構労力がいるのでは、という感じがしている。それと、まずはデータコンストラクタとパターンマッチの感覚を理解するのが、案外多くの人にとって最初の山なのかなーと思った。

Haskell for Great Goodで使われている英語は平易なので、オンラインで無料の原文を読むのをおすすめする。後でまた同じところではまると嫌なので、自分の理解している範囲で覚え書きとして記してみた。現時点ではポイントを外している可能性もあることを言い訳として付け加えておく。修正があればその都度更新予定。