🔰

モナド入門:プログラミング言語を横断する共通の特徴から学ぶ

に公開3

Discussion

colacola

記事を書いて下さりありがとうございます。
モナドが理解出来ていないので質問させてください。

記事にあるように
bをMaybe String
とした場合
bindのところの画像の真ん中は
String -> Maybe Maybe String
となってしまうのではないかと思ってしまうのですがなぜ入れ子になってしまわないのかが理解できていません。
もし回答頂けましたら嬉しいです。

funnycatfunnycat

colaさん
記事を読んでいただきまして、ありがとうございます。

ご質問いただいた内容について、回答いたします。

冗長になってしまうことをご容赦いただきたいのですが、質問いただいた節について、あらためて説明してみます。

まず『bindを使うと何が嬉しいか』の節では次のような前提で話を進めています。

  • m a の a の型を変換したい
    (この例ではMaybe StringStringIntに変換したい)
  • 変換の際、mという文脈は保ちたい
    (この例ではMaybeの文脈を保ちたい)

そしてこういった変換が行えそうな関数としてmapbindがあることを紹介しています。

  • mapではa -> bという型の関数を受け取る
  • bindではa -> m bという型の関数を受け取る

この前提のもと、それぞれの変換の関数で、Maybe Intを返したらどうなるかを考えています。
ここについて上記の前提を踏まえつつ、abなどを少しずつ置換しながら今一度説明してみます。

まずmapm a -> (a -> b) -> m bという型の関数です(引数の順序は入れ替えてますが)。

  1. まずmMaybeで置き換えます。
    Maybe a -> (a -> b) -> Maybe b
  2. 次にaStringに置き換えます。
    Maybe String -> (String -> b) -> Maybe b
  3. 変換の関数ではMaybe Intを返したいという前提があるので、最後にbMaybe Intに置き換えます。
    Maybe String -> (String -> Maybe Int) -> Maybe (Maybe Int)

同じことをbindについても行ってみます。
bindm a -> (a -> m b) -> m bという型の関数です。

  1. まずmMaybeで置き換えます。
    Maybe a -> (a -> Maybe b) -> Maybe b
  2. 次にaStringに置き換えます。
    Maybe String -> (String -> Maybe b) -> Maybe b
  3. 変換の関数ではMaybe Intを返したいという前提があるので、最後にbMaybe Intに置き換えます。
    Maybe String -> (String -> Maybe Int) -> Maybe Int

さて、ここであらためて質問を読み返しながら回答を書いてみます。

記事にあるように bをMaybe String とした場合

ここについては、前提として変換の関数で返したいのはMaybe Intなのですが、
bindの場合、変換の関数で返す型はm bなので、bそのものをMaybe Intに置き換えずとも、m bを返すことになっているので、やりたいことが素直に実現できます。

ですので

なぜ入れ子になってしまわないのか

については、やりたいことを実現するにあたって、入れ子にする必要がない、というのが回答になります。

以上、あらためて説明してみましたが、ご質問に対してお答えできていたら幸いです。

たけぴょんたけぴょん

何度もHaskellのモナド(とApplicative)に挫折していましたが、この記事の文脈という表現が自分の中でイメージがマッチして理解が深まったような気がします。とても助かりました。

少々記事内容から飛んでしまうのですが質問させてください。
圏論の文脈ではモナドはCを圏として関手T:C \rightarrow Cと2つの自然変換\eta : 1_C \rightarrow T\mu : T^2 \rightarrow T .... と定義されています(Wikipediaの定義を引用)が、Haskellでのreturnが自然変換\eta : 1_C \rightarrow T、>>=が自然変換\mu : T^2 \rightarrow Tに対応するのでしょうか?
お手隙あればご回答いただけると助かります。