モナドハンズオン前座
DESCRIPTION
わかめモナ化の発表資料です。TRANSCRIPT
![Page 1: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/1.jpg)
モナド概論
bleis-tift
November 17 2012
![Page 2: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/2.jpg)
モナド概論
モナドハンズオン前座発表
bleis-tift
November 17 2012
![Page 3: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/3.jpg)
自己紹介
id:bleis-tift / @bleis
名古屋 Scala / なごやか Scala
Scalaが好きです。でも F#のほうがもーっと(ry
Microsoft MVP for Visual F#
![Page 4: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/4.jpg)
この会の趣旨(だったもの)
モナドで躓いている人たちに、「モナドってこんな感じのものだよ」っていうのを丁寧に教える会
決して「うわ、あの人たちこわっ!」って雰囲気にならないような感じ
より多くの人が「モナドって便利!」って思ってもらえたら素敵じゃない?
どうしてこうなった・・・
![Page 5: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/5.jpg)
対象
次のどれかに当てはまる人を一応対象とします。
何らかの静的型付けの関数型言語でプログラムが書ける
モナドを勉強して挫折したことがある
Maybeモナドくらいなら・・・
分からない所は発表中でも構わずに質問をお願いします。分かる範囲でお答えします。
![Page 6: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/6.jpg)
モナド
![Page 7: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/7.jpg)
モナドとは
とりあえず、
型パラメータを 1つとる型と、
>>=(バインド)演算子と、
return関数
が出てきたら「モナド」というゆるい感じからはじめます。が、しばらく出てきませんので頭の片隅に置いておいてください。
![Page 8: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/8.jpg)
Maybeモナド
![Page 9: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/9.jpg)
連続したnullチェックのだるさ
こんなコードはだるい。
.
連続した nullチェック
.
.
.
let a = f1 x
if a <> null then
let b = f2 a
if b <> null then
...
こんなだるいことしてるとどっかでミスる (いわゆるぬるぽ)。returnがある言語だと、returnすればいいんじゃね?ってなることもある
![Page 10: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/10.jpg)
途中で return
.
連続した nullチェック (Scala)
.
.
.
val a = f1(x)
if (a == null)
return null
val b = f2(a)
if (b == null)
return null
...
うーん、でもやっぱりだるい。本当にやりたかったことが埋もれてしまっている。
![Page 11: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/11.jpg)
爆ぜろリアル!
俺はこう書きたいんだ!
.
理想形 1
.
.
.
let a = f1 x
let b = f2 a
...
もしくは・・・
.
理想形 2
.
.
.
x |> f1 |> f2 |> ...
どちらにしても nullチェックなんてしたくない!!!
![Page 12: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/12.jpg)
とりあえず
ぬるぽが起きないようにしましょう。
.
option型を定義
.
.
.
type option<’T> = None | Some of ’T
これで stringと option<string>が別の型に!
option<string>に対して stringのメソッドは直接呼び出せなくなった
シグネチャに「値が無いかもしれない」という情報を埋め込めるようになった
Scalaの場合は sealedなクラスとしてOptionを作り、Noneという case objectと Someという case classを用意
![Page 13: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/13.jpg)
option型で書き直す
.
連続した nullチェック (再掲)
.
.
.
let a = f1 x
if a <> null then
let b = f2 a
if b <> null then
...
.
各関数が optionを返すように書き換え
.
.
.
match f1 x with
| Some a ->
match f2 a with
| Some b ->
...
| None -> None
| None -> None
![Page 14: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/14.jpg)
全然だめだ!
![Page 15: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/15.jpg)
そこで!こんな演算子を導入してみます。
.
>>=演算子の導入
.
.
.
let (>>=) opt (f: ’a -> option<’b>) =
match opt with
| Some x -> f x
| None -> None
.
ネストしたパターンマッチ (再掲)
.
.
.
match f1 x with
| Some a ->
match f2 a with
| Some b ->
...
| None -> None
| None -> None
Someの場合の処理を関数で表現すると・・・
![Page 16: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/16.jpg)
こう!
.
>>=演算子を使って書き直し
.
.
.
f1 x >>= (fun a ->
f2 a >>= (fun b ->
...
))
関数のネストになった!
.
ネストしたパターンマッチと比べてみる (再掲)
.
.
.
match f1 x with
| Some a ->
match f2 a with
| Some b ->
...
| None -> None
| None -> None
![Page 17: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/17.jpg)
再確認
.
>>=演算子 (再掲)
.
.
.
let (>>=) opt (f: ’a -> option<’b>) =
match opt with
| Some x -> f x
| None -> None
.
ネストしたパターンマッチ (再掲)
.
.
.
match f1 x with
| Some a ->
match f2 a with
| Some b ->
...
| None -> None
| None -> None
OKですか?
![Page 18: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/18.jpg)
色々書き換えてみる
.
元のコード (再掲)
.
.
.
f1 x >>= (fun a ->
f2 a >>= (fun b ->
...
))
.
ネストを取り除く
.
.
.
f1 x >>= (fun a ->
f2 a) >>= (fun b ->
f3 b) >>= (fun c ->
...
)
最後の閉じかっこが増えなくなった!
![Page 19: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/19.jpg)
色々書き換えてみる
.
元のコード (再掲)
.
.
.
f1 x >>= (fun a ->
f2 a >>= (fun b ->
...
))
.
F#の本気
.
.
.
f1 x >>= fun a ->
f2 a >>= fun b ->
f3 b >>= fun c ->
...
括弧?何それおいしいの?
![Page 20: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/20.jpg)
色々書き換えてみる
.
元のコード (再掲)
.
.
.
f1 x >>= (fun a ->
f2 a >>= (fun b ->
...
))
.
関数を直接渡す
.
.
.
x |> f1 >>= f2 >>= ...
お・・・?
.
理想形 2にそっくりや!(再掲)
.
.
.
x |> f1 |> f2 |> ...
![Page 21: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/21.jpg)
理想1も実現したい!
F#や ScalaやHaskellではできるんです!それぞれ、
F#・・・コンピュテーション式
Scala・・・for式
Haskell・・・do式
という (モナド用の)構文が用意されています。>>=演算子はそれぞれ、
F#・・・Bindメソッド
Scala・・・flatMapメソッド
Haskell・・・>>=演算子
に対応します。>>=演算子以外に・・
![Page 22: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/22.jpg)
>>=演算子以外に必要なもの
F#・・・Returnメソッド
Scala・・・mapメソッドとユニットコンストラクタ
Haskell・・・return関数
が必要になります。
![Page 23: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/23.jpg)
横道:Scalaのmapメソッド
Option[T]にT => Uな関数を適用し、Option[U]を作るメソッド
flatMapとユニットコンストラクタがあれば作れる
.
.
// Option[T]のメソッド (thisは Option[T])
def map[U](f: T => U): Option[U] =
this.flatMap { x => Some(f(x)) }
にも関わらず必要なのは効率のため?1
1returnをそのまま提供するのが色々面倒だからっぽい?
![Page 24: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/24.jpg)
本題に戻って理想 1の実現に必要なクラスを用意します。
.
MaybeBuilder
.
.
.
type MaybeBuilder() =
member this.Bind(opt, f) =
match opt with
| Some x -> f x
| None -> None
member this.Return(x) = Some x
let maybe = MaybeBuilder()
>>=演算子の定義はこうでした。
.
>>=演算子の定義 (再掲)
.
.
.
let (>>=) opt (f: ’a -> option<’b>) =
match opt with
| Some x -> f x
| None -> None
![Page 25: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/25.jpg)
また横道:Scalaだと
Optionクラスにメソッドを定義することになります。
.
.
def flatMap[U](f: T => Option[U]): Option[U] =
this match {
case Some(x) => f(x)
case None => None
}
def map[U](f: T => U): Option[U] =
this match {
case Some(x) => Some(f(x))
case None => None
}
![Page 26: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/26.jpg)
本題に戻って
さっきのmaybeを使うと・・・
.
こう書けるようになる!
.
.
.
maybe {
let! a = f1 x
let! b = f2 a
...
return 結果}
.
理想 1と比べてみる (再掲)
.
.
.
let a = f1 x
let b = f2 a
...
もうちょっと具体的な例で説明します。
![Page 27: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/27.jpg)
http://d.hatena.ne.jp/mzp/20110205/monad
「dbというMapに格納されている”x”と”y”を加算する」
.
理想
.
.
.
let db = Map.ofList [("x", 1); ("y", 2); ("z", 3)]
let result =
let x = db |> Map.find "x"
let y = db |> Map.find "y"
x + y
.
実際
.
.
.
let result = maybe {
let! x = db |> Map.tryFind "x"
let! y = db |> Map.tryFind "y"
return x + y
}
![Page 28: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/28.jpg)
ざっくりどうなっているか
maybe { } で囲まれている部分がlet!がBindの呼び出しに(後続の処理はラムダ式で包まれる)
returnがReturnの呼び出しに
変形されます。ちなみに Scalaでは、returnに相当するのは yieldで、for式の括弧の外に来ます。
![Page 29: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/29.jpg)
こうなるわけです
.
これが (再掲)
.
.
.
let result = maybe {
let! x = db |> Map.tryFind "x"
let! y = db |> Map.tryFind "y"
return x + y
}
.
こう変形される
.
.
.
let result =
maybe.Bind(db |> Map.tryFind "x", fun x ->
maybe.Bind(db |> Map.tryFind "y", fun y ->
maybe.Return(x + y)))
この「ネストを平坦化させる」のがモナド用構文の便利な所です。
![Page 30: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/30.jpg)
注意!
理想形に似てるからって展開はできません。
.
これは無理
.
.
.
let result = maybe {
return (db |> Map.tryFind "x") +
(db |> Map.tryFind "y")
}
まぁScalaの場合は
.
Scala版
.
.
.
val result = for {
x <- db.get("x")
y <- db.get("y")
} yield x + y
なので大丈夫だとは思いますが。
![Page 31: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/31.jpg)
ここまでのまとめ
>>=演算子でネストをフラットに>>=演算子の後ろに処理を隠す
>>=演算子は | >演算子に似ているモナド用の構文でより自然に
実はただの式変形プログラマがカスタマイズできるシンタックスシュガーてきな
Maybeモナドが何なのか分からなくても、モナド用の構文で便利に使える←大事
![Page 32: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/32.jpg)
Stateモナド
![Page 33: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/33.jpg)
さて、Stateモナドですよ
Maybeモナドはもっとも理解が容易なモナドの一つ
Stateモナドは理解が難しいモナドの一つ
ハンズオンで実装するにあたって、混乱しないための知識が必要
難しいかもしれませんが、数をこなせばそのうち分かります (そのためのハンズオン)
さて行きましょう!
![Page 34: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/34.jpg)
Stateモナドとは
モナドのすべてより:
利用場面:状態を共有する必要のある一連の操作から計算を構築する
「再代入なしで、再代入と同じような挙動を実現する」とかって理解でもよい。「F#にも Scalaにも再代入あるじゃん!何に使うのさ!」ってのはとりあえず置いといてください。
![Page 35: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/35.jpg)
再代入なしで状態の取得や更新を実現するには
関数に他の引数と一緒に「状態」も渡す
他の戻り値と一緒に「次の状態」も返すようにする
状態のやりくりを頑張る
だるそう!
![Page 36: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/36.jpg)
実際だるい
.
自分で状態を管理する
.
.
.
let x, state1 = f1 (a, initialState)
let y, state2 = f2 (x, state1)
let z, state3 = f3 (y, state2)
...
そこで Stateモナドですよ!
![Page 37: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/37.jpg)
Stateモナドの型
.
State型
.
.
.
// 状態を受け取って、// 値と次の状態のタプルを返す関数type State<’TState, ’T> =
’TState -> (’T * ’TState)
あれ、モナドって型パラメータは一つだったはずじゃ?→状態を表す型を固定化すればいいのさ!
![Page 38: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/38.jpg)
バインドの後ろに何を隠すか
状態の管理を隠しましょう。
.
StateBuilder
.
.
.
type StateBuilder () =
member this.Bind(stateM, rest) =
fun state ->
let x, nextState = stateM state
rest x nextState
member this.Return(x) =
fun state -> (x, state)
let state = StateBuilder()
バインドわけわかんない><。
![Page 39: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/39.jpg)
Maybeモナドとの共通点を探す
.
Maybeモナドのバインド
.
.
.
// type Option<’T> = None | Some of ’T
member this.Bind(opt, rest) =
match opt with
| Some x -> rest x
| None -> None
.
Stateモナドのバインド
.
.
.
// type State<’TState, ’T> = ’TState -> (’T * ’TState)
member this.Bind(stateM, rest) =
fun state ->
let x, nextState = stateM state
rest x nextState
Bindメソッドの型 (モナドと関数を受け取り、モナドを返す)
restの型 (モナドの中の値を受け取り、モナドを返す)
取り出した値を restに渡している
![Page 40: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/40.jpg)
バインドの中を詳しく見てみる
.
.
// type State<’TState, ’T> = ’TState -> (’T * ’TState)
member this.Bind(stateM, rest) =
fun state ->
let x, nextState = stateM state
rest x nextState
stateMは State型 (なので、関数)
stateMに状態を渡すと、値 xと次の状態 nextStateのタプルが取得できる先ほどのだるいコードはここに相当
restは後続処理を表す関数で、戻り値は State型 (関数)
restは元々引数を 1つ取るため、カリー化された 2引数関数とみなせる
rest xをそのまま Bindの戻り値として返しただけだと「次の状態」が伝播できない
rest xに「次の状態」を渡してしまい、全体をラムダ式で包みState型に
![Page 41: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/41.jpg)
・・・
狐につままれた感じですかね実際に実装して処理を追うと理解の助けになりますので頑張ってください
![Page 42: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/42.jpg)
使ってみる
.
stateを使ってみる
.
.
.
let result = state {
let! initVal =
fun initStat -> (initStat, initStat)
let x = initVal + 1
do! fun _ -> ((), x * 2)
return x
}
let res1 = result 0 // => (1, 2)
let res2 = result 10 // => (11, 22)
バインドの定義はこちら
.
.
member this.Bind(stateM, rest) =
fun state ->
let x, nextState = stateM state
rest x nextState
![Page 43: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/43.jpg)
こんなもの使えるかー!
![Page 44: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/44.jpg)
ごもっとも
なので補助関数を定義しましょう!
.
.
let result = state {
let! initVal =
fun initStat -> (initStat, initStat) // 状態の取得let x = initVal + 1
do! fun _ -> ((), x * 2) // 状態の設定return x
}
状態の取得と更新を関数化します。
.
補助関数
.
.
.
let get = fun stat -> (stat, stat)
let put newStat = fun _ -> ((), newStat)
この補助関数を使うと・・・
![Page 45: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/45.jpg)
こうなります!
.
state完全版
.
.
.
let result = state {
let! initVal = get
let x = initVal + 1
do! put (x * 2)
return x
}
補助関数を定義する前とは大違い。
.
補助関数定義前 (再掲)
.
.
.
let result = state {
let! initVal =
fun initStat -> (initStat, initStat)
let x = initVal + 1
do! fun _ -> ((), x * 2)
return x
}
let res1 = result 0 // => (1, 2)
let res2 = result 10 // => (11, 22)
![Page 46: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/46.jpg)
getとput
なんでアレで状態の取得や更新ができるの・・・?
バインドの定義と、getや putの定義を追えばわかりやすいかも
![Page 47: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/47.jpg)
getgetとバインドの定義
.
.
let get = fun stat -> (stat, stat)
.
.
member this.Bind(stateM, rest) =
fun state ->
let x, nextState = stateM state
rest x nextState
stateMが getだった場合
.
.
fun state ->
let x, nextState = (fun stat -> (stat, stat)) state
rest x nextState
現在の状態 (state)を弄らずに値と次の状態として使う
.
.
fun state ->
let x, nextState -> state, state
rest x nextState
![Page 48: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/48.jpg)
続・get
更に展開すると
.
.
fun state ->
let x, nextState -> state, state
rest x nextState
最終的にこう
.
.
fun state -> rest state state
これは何を意味するか?xは表に出てくる値を表し、restは後続処理を表す表に出てくる値として、現在の状態を渡すことになる次の状態として、現在の状態を弄らずに渡すことになる結果、「値としては現在の状態が取得」できるし、状態もいじらない!
![Page 49: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/49.jpg)
putputとバインドの定義
.
.
let put newStat = fun _ -> ((), newStat)
.
.
member this.Bind(stateM, rest) =
fun state ->
let x, nextState = stateM state
rest x nextState
stateMが putだった場合
.
.
fun state ->
let x, nextState = (fun _ -> ((), newStat)) state
rest x nextState
現在の状態 (state)を捨てている
.
.
fun state ->
let x, nextState = (), newStat
rest x nextState
![Page 50: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/50.jpg)
続・put
最後までは展開しないけど・・・
.
.
fun state ->
let x, nextState = (), newStat
rest x nextState
これは何を意味するか後続処理に値として何も渡さない (()を渡す)次の状態として、put関数に渡された値を使う結果、「指定した値で状態を更新」できるし、表に出てくる値は生成しない
![Page 51: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/51.jpg)
ここまでのまとめ
バインドの後ろに状態の管理を隠したのがStateモナド
丁寧に読み解けばなんとなくの理解は得られる(と、思う)再代入なしで可変な状態を実現できた
補助関数がないとつらいgetと put
補助関数の動作について展開して追ってみた
![Page 52: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/52.jpg)
まとめ?
![Page 53: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/53.jpg)
さて
Maybeモナドと Stateモナドという異なる性質を持つ 2つのモナドを見ましたこの 2つのモナドは、
bind:Monad<’T> -> (’T -> Monad<’U>) -> Monad<’U>return: ’T -> Monad<’T>
という 2つの関数を持つという共通点しかありませんでした (実際にやる処理は全然違う)
様々なモナドが存在し、様々な bindと returnを提供しています
モナドは「何をやるか」は決めず、記法を提供するだけ
それでは、色々なモナドを実装していきましょう!
![Page 54: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/54.jpg)
これから先のこと
モナド自体が何のか?という問いには答えていない
無理><そんなことより色んなモナド学ぼう!というスタンス気になったら調べてみるといいとは思うけど、おススメしない
色んなモナドを学ぶためのある程度の道しるべをつけておきます
その後は自分で歩けると信じて
![Page 55: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/55.jpg)
モナドのすべて
http://www.sampou.org/haskell/a-a-monads/html/index.html
英題は「All Abouts Monads」
分かりやすいかどうかは別として、色々なモナドに触れることができる
エンコーディングは euc-jpで
![Page 56: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/56.jpg)
モナドとモナド変換子のイメージを描いてみた
http://d.hatena.ne.jp/melpon/20111028/1319782898
モナド変換子はとりあえず置いといて・・・
各関数のイメージがよくつかめる
![Page 57: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/57.jpg)
モナドはメタファーではない
http://eed3si9n.com/ja/monads-are-not-metaphors
たとえに頼らずに説明している
プログラムの中からモナドを見つけるための感覚つくりに
![Page 58: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/58.jpg)
サルでもわかる IOモナド
url
http://blogs.dion.ne.jp/keis/archives/5880105.html
http://blogs.dion.ne.jp/keis/archives/5907722.html
http://blogs.dion.ne.jp/keis/archives/5984552.html
IOモナドを倒すために
![Page 59: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/59.jpg)
モナドチュートリアル
http://www.slideshare.net/tanakh/monad-tutorial
理解できるかどうかは置いておいて、一度一通り読んでみる
![Page 60: モナドハンズオン前座](https://reader033.vdocuments.pub/reader033/viewer/2022060112/556f6941d8b42a9d338b49f8/html5/thumbnails/60.jpg)
最後に一つ忠告しておきます
Wikipediaは見ない方がいい