すごいHaskell、ハスケル子と学ぼう！

「**すごいHaskellたのしく学ぼう！**」という本を読みました。
せっかく関数型言語の本を読んだので、今回は**関西型言語**を用いて、学んだ内容について綴っていきたいと思います。

## ある日、某会社にて

ワイ「なぁ、ハスケル子ちゃん」
ワイ「Haskellの記事とか読んでると出てくる、**モナド**ってアレ何なん？」

ハスケル子「**型クラス**ですね」

ワイ「型クラス・・・」
ワイ「ごめん、ぜんぜん分からんわ」
ワイ「型クラスって何・・・？」

ハスケル子「**型の分類**みたいな感じです」
ハスケル子「**class**って、**分類**とか**同類**って意味を持っているので」

ワイ「型の分類・・・」
ワイ「型自体がそもそも、**数値**とか**文字列**とか」
ワイ「そういった**分類**みたいな感じなのに、それを更に**分類**すんの・・・？」
ワイ「どどどどういうこと・・・？」

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/21dc85fb-fcbb-eadc-f726-2b5b39e5766b.jpeg" width="400">

ワイ「舌打ちせんといてや・・・」

## Int型とFloat型って似てるよね
ハスケル子「えっと、じゃあ・・・」
ハスケル子「Int型とFloat型が**似てる**っていう感覚は分かりますか？」

ワイ「それは分かるで」
ワイ「両方とも、数値っぽい型やもん」

ハスケル子「そうですよね」
ハスケル子「**型の分類**として同じだな、って感じがしますよね」

ワイ「ああ、確かに」
ワイ「同じ分類の型って感じやな」
ワイ「**型の分類**っていう意味が何となく分かったわ」

ハスケル子「じゃあ・・・」
ハスケル子「その**数値っぽい**っていうのは、具体的にどんな感じですか？」

ワイ「ええと、数値っぽいっていうのは・・・」
ワイ「足したり引いたり、掛け算したりできる感じや」

ハスケル子「ですよね」
ハスケル子「それを明確に定義したものが**型クラス**です」
ハスケル子「Int型とFloat型は、同じ**Num型クラス**に属してるんです」
ハスケル子「属しているというか、Num型クラスを**実装している**んですけど」

ワイ「ほえ〜」
ワイ「まだよう分からんけど」
ワイ「数値型全般を表す**Num**っていう**型クラス**があるんやね」

ハスケル子「そうです」

## 型クラスが定義しているもの

ハスケル子「**Num型クラス**の定義には」

> **(+), (*), (-) を実装すべし！**

ハスケル子「みたいな事が書いてあります」
ハスケル子「つまり───」

> **足し算・掛け算・引き算**ができること！

ハスケル子「───みたいな**ルール**ですね」
ハスケル子「そして、実際にInt型やFloat型はそのように実装されなければなりません」

ワイ「ほえ〜」
ワイ「**型クラス**は、**型たちの振る舞い**を定義してんねやな」
ワイ「**この型たちはこうあるべし！**って」

ハスケル子「その通りです」

## じゃあモナドは？

ワイ「**Num型クラス**を実装した**Int型**や**Float型**は」
ワイ「足し算や引き算ができる、という共通の特徴を持っている・・・」
ワイ「そこは何となく分かったわ」
ワイ「ほんで、さっきハスケル子ちゃん」
ワイ「**モナドも型クラス**やって言うてたやん？」

ハスケル子「はい」

ワイ「ほな、**Monad型クラス**っていうのがあるってこと？」

ハスケル子「そうです」
ハスケル子「正しくは・・・」
ハスケル子「**Monad型クラス**を実装した型たちのことを**モナド**って呼びます」

ワイ「ほえ〜」
ワイ「ほな、**Monad型クラス**に属する型たちは、どんな共通の特徴を持ってんの？」

ハスケル子「Monad型クラスを実装した型たちは」
ハスケル子「**文脈を持った値**を表現できます」

## 文脈を持った値・・・
ワイ「ごめん、ぜんぜん分からんわ」
ワイ「実際、どんな型があんの？」

ハスケル子「例えば、**Maybe型**とか**List型**とかが**モナド**ですね」

ワイ「おお、**Maybe**か」
ワイ「**Elm**にもある型やね」

ハスケル子「はい、あれとほぼ同じです」
ハスケル子「Maybe型の値は、**文脈を持ってる**じゃないですか？」

ワイ「いや、それがよう分からんわ・・・」

ハスケル子「じゃあ、Maybe型ってどんな時に使います？」

ワイ「どんな時っていうか、**Elm**だと・・・」
ワイ「**`String.toInt`**っていう関数で、**文字列を数値に変換**しようとすると」
ワイ「**Maybe Int型**の値になってしまうわ」

ハスケル子「それは何故ですか？」

ワイ「それは、**文字列は必ずしも数値に変換できるとは限らん**からや」
ワイ「例えば`"5"`とか`"80"`とかいう文字列やったら数値に変換できるけど」
ワイ「お問い合わせフォームとかで、ユーザが`"うんこ"`とか入力してくるかもしれんから」
ワイ「**数値に変換できんような文字列**が`String.toInt`関数に渡されてしまうこともあって」
ワイ「ちゃんと数値に変換できる確証はない」
ワイ「だから**Maybe Int型**の値になるんや」

ハスケル子「そうですね」
ハスケル子「つまり**Maybe Int型**の値っていうのは・・・」
ハスケル子「**ちゃんと数値に変換できたかもしれないし、できなかったかもしれない・・・**」
ハスケル子「そういう、**文脈を持った値**ですよね」

ワイ「確かに・・・」

## 不確実な値・・・その「不確実な」という文脈を表現できる

ハスケル子「**数値に変換できてなかった場合の処理**も`case`式などでちゃんと書いておかないと、**コンパイルが通らない**」
ハスケル子「そういう制限を設けることで、Elmは**実行時エラーが起こらない**ようになっていますよね？」

ワイ「ああ、せやな」
ワイ「ユーザ入力から受け取る値とか、そういう」
ワイ「実行時にならんと**どんな値が入ってくるのか分からん**ような、**不確定性のある値**も」
ワイ「**事前に検査して安全に扱える**、っていう**不思議な仕組み**やったね」

ハスケル子「はい」
ハスケル子「文脈に包まれた値を表現できることで」
ハスケル子「なんか**シュレーディンガーの猫**みたいな値すらも」
ハスケル子「事前コンパイルで検査できちゃう」
ハスケル子「そんな感じです」

ワイ「文脈ってハンパないな」

ハスケル子「そうなんです」

## 文脈に包まれた値の扱い方
ハスケル子「でも、値が文脈に包まれてるせいで面倒なこともあって」
ハスケル子「例えば**Maybe Int型**の値は**そのままだと計算したりできない**じゃないですか？」

ワイ「せやな」
ワイ「`case`式を使って」
ワイ「数値が入ってた場合と、入ってなかった場合の」
ワイ「両方の処理を書かないとあかんねん」

ハスケル子「で、そこを上手いことしてくれる関数がありますよね」
ハスケル子「Elmだと`Maybe.map`とか」

ワイ「せやね」
ワイ「例えば、2つの整数を足すだけの`add`っていう足し算関数があったとして」
ワイ「`add`関数が受け取れるのは**Int型**だけやから」
ワイ「**Maybe Int型**の値を足し算しようとしてもコンパイルエラーになってしまうねん」
ワイ「せやけど`Maybe.map2`っていう関数を使って`add`関数を変身させてあげると」
ワイ「**Maybe Int型**の値同士を足し算できる関数が出来あがんねん」

ハスケル子「関数の**持ち上げ**ってやつですね」

ワイ「あと、Elmには`Maybe.andThen`っていう関数もあって」
ワイ「その`Maybe.andThen`いう関数も」
ワイ「**Int型**しか受け取れん関数を」
ワイ「**Maybe Int**を受け取れる関数に変身させてくれたりするな」

ハスケル子「はい」
ハスケル子「値が文脈に包まれていて**そのままでは計算できない**から」
ハスケル子「そこを上手くやってくれる関数が用意されてるってことですね」

## Haskellには`>>=`がある

ハスケル子「Haskellの場合だと、Elmの`Maybe.andThen`関数に相当する」
ハスケル子「`>>=`という演算子が用意されていて」
ハスケル子「その子が上手いことモナド絡みの処理を繋いでくれます」
ハスケル子「`>>=`は**バインド**と読むんですけど」
ハスケル子「何か連続で処理をしているときに、途中で**値が文脈に包まれてしまって**」
ハスケル子「あ、次の関数に渡すべき型とズレちゃった！」
ハスケル子「ってなりそうなときも」
ハスケル子「そこを**上手いことハック**してくれるわけです」

ワイ「なるほどな〜」

## まとめ
- モナドは**文脈に包まれた値**を表現できる型
- 文脈に包まれたままの値には、**普通の関数を適用できない**
- でも、そこを**上手いことハックする術**（`>>=`など）がちゃんと用意されている
- モナドは`>>=`を実装すべし！ということは**Monad型クラス**に定義されている

ハスケル子「って感じですね」

ワイ「おおきにやで、ハスケル子ちゃん」
ワイ「なんとなく分かったわ」

**〜おしまい〜**