モナドとは
関数型言語でIOとかの副作用を扱う方法として教わった。
でも、本質的には違う!!
プログラミングについてとらえなおす。
プログラムの関数とはある型A(のインスタンスa)からある型B(のインスタンスb)への写像である。
各型Aは内部的にAのインスタンスを区別する比較基準を持っている。関数型言語の純粋関数とは引数がAの型の意味で等しければその返り値も等しいという性質を満たす関数である。ここで特別な型としてUnit型がある。Unit型は区別できないので、Unit型を返す関数は完全に純粋関数である。(返り値の意味で迷う要素はない)
ここで、IOを考えてみよう。
doInput関数がもしキーボードから入力待ちをして、入力を返す関数だとすると、それは呼び出すごとに返り値が変わるので純粋関数ではない!これがうざいので、Monad型でラップしてみる。つまり、doInput関数を呼ぶとdoInput()はMonal型を返し受け取った値はMonad型の中にあるように扱うのである。こうすると、doInput(Unit):Monadと書けて、doInput()の返り値が変わることはない。
しかし、このままではMonalの中でラップされている入力された値に触れられない!なので、Monad.bind[T,U](Monad[T],T => U): Monad[U]を考える。これによって内部の値に関数を適用できるようになる。しかし、その返り値もMonaldにラップされているのでそのまま使うとはできなくて、bindを介して関数適用することしかできない。
もう一つの関数としてMonald[T].toMonald(T):Monadが必要である。これがないとMonad型を作れない。
このように返り値をラップして関数適用のみを許したような、変数の制限版がモナドである。モナドにいろんな文脈を持たせることで関数適用だけでプログラムを作れるような純粋間推移型言語が存在するのである。
モナドの例
例えば、Optional[T]はMonadである。Optional[T].map(T=>U):Optional[U]がbindにあたる。しかし、Optional[T]にはgetとかunwrapが実装されているので、上のモナドが純粋性を作り出すよな性質はない。Listを作る文脈に副作用は不要なので問題ない。
List[T]もモナドである。List[T].map(T=>List[U]):List[U]がbindに当たる。これも同様に純粋性を作り出す性質はないが、Listを作る文脈に副作用は不要なので問題ない。
以上のようにいろんなMonad的なものは存在する。人間もモナドである。外界からの影響が脳に蓄積されているが、それは状況のもとでの行動からしかわからない。
考えたこと
純粋関数型言語的な目線で行くとMonaldから値を取り出すという行為をしたくないように思う。Monadを使う関数はUnit型を返してほしい。つまり内部でMonaldを使用する関数の連鎖を終わりまで記述してほしいと思うのではないかと感じた。