70052


# 前置き

`Functor`や`Monad`を理解するためには`コンテキスト`を理解することが大切と考えます。  
`コンテキスト`については下記記事のように言及しているものがあります（ほかにもたくさんあります）。

**引用:**

[Functor - HaskellWiki](https://wiki.haskell.org/Functor)

> The Functor typeclass represents the mathematical functor: a mapping between
> categories in the context of category theory. In practice a functor
> represents a type that can be mapped over.

[SwiftのOptional型を極める -
Qiita](https://qiita.com/koher/items/c6f446bad54442a28bf4#%E3%83%A2%E3%83%8A%E3%83%89%E3%81%A8%E3%81%97%E3%81%A6%E3%81%AEoptional)

>
> モナドというのは、モナドでくるまれた中の世界ではモナドを気にせずに処理が記述でき、外からみるとモナドでくるまれているという、外と中を分離するための仕組みです。

## コンテキストの私の理解

さて `コンテキスト`
という言葉はそれこそ"文脈"によって意味がすこし変わってきそうですが（Perlにも`コンテキスト`という考えがありますし）、Hakellに置いて`コンテキスト`というと、"一度その状態（コンテキスト）に入ったらその影響を外部に漏らしたくない"
というような意味合いだと思っています。

# >>= を使いたい場面とは？

さて、ここになんのヘンテツもない 引数を受け取って+1して返す関数を定義します

[code]

    inc x = x + 1
    
[/code]

これを `Functor` を使えば、`Maybe`コンテキストの仲間に加えることができます。

[code]

    hoge = Just 1
    inc <$> hoge
    
[/code]

一方 Monad を使うのであれば、同じように +1 して返す関数は下記になると考えます。

[code]

    incWrapedJust x = Just(x + 1)
    
[/code]

そして使い方は

[code]

    hoge = Just 1
    hoge >>= incWrapedJust
    
[/code]

こんな感じ。

でも、 **ここで疑問に思いました** 。

**コンテキストのことを意識しているプログラマなのであれば、わざわざこんな引数と返り値でコンテキストがチグハグな関数を作るでしょうか？**

[code]

    hoge = Just 1
    incJustJust (Just x) = Just(x + 1)
    incJustJust hoge
    
[/code]

こんな風に引数と返り値で同じコンテキストの関数を作って使えば済む話ではないでしょうか？

## 疑問

  * コンテキストのことを意識しているのであれば、なぜわざわざこんなチグハグな関数をつくるのでしょうか？ 
    * 作りたい、使いたいタイミングはあるのでしょうか？

たんなる疑問ではお答えしづらいかと思いますので、念の為に回答として期待することを書きます。

たとえば「Haskellでよくつかわれているhogehogeという関数はこういったチグハグな関数なので、使わざるを得ない」や「fugafugaといった場面ではチグハグな関数を作って使いたいことがある」等です。（もちろん他の私の想像もしていないような回答でもよいと思います）

* * *

追記:

[@YAMAMOTO
Yujiさんの回答](https://ja.stackoverflow.com/a/70052/9008)でチグハグな関数が生まれる（使いたい）場面がとてもよくわかりました。
実際に試してみようと下記コードを書いてみました。

[code]

    import qualified Data.Map as Map 
    
    dict = Map.fromList [("key1", "val1"), ("key2", "val2")]
    f x = Just ("Mr." ++ x)
    
    Map.lookup "key1" dict >>= f -- Just "Mr.val1"
    
[/code]

これで確かにチグハグな関数が生まれる例はわかったのですが、 `>>=` を使いたい場面がまだわからないままです。上記コードの `f関数` は
私がはじめに書いた `incWrapedJust x = Just(x + 1)` くらい現実的ではない関数に感じます。

たとえば、 `key1`で取り出した値をさらに別のキーにして取り出すのであれば多少現実的かなと思い下記のコードを書いてみたのですが、

[code]

    import qualified Data.Map as Map 
    
    dict = Map.fromList [("key1", "key2"), ("key2", "val2")]
    Map.lookup "key1" dict >>= Map.lookup dict
    
[/code]

エラーになってしまいました。（上記のコードを成功させたいわけではなく、 `>>=`
と処理がつながっていく自然な例が知りたいです。上記が動けば、同じデータ構造からそんな検索かけることあるかよって気持ちにもなりますが、すこしは自然なコードかと思います。）


CC BY-SA 4.0
2020-09-01T12:06:08.567
70051
2020-09-02T00:42:28.647
2020-09-01T14:23:14.160
9008
9008
question
haskell
Monadクラスの >>= はどのような場面で使いますか？


> 一方 Monad を使うのであれば、同じように +1 して返す関数は下記になると考えます。
[code]

>     incWrapedJust x = Just(x + 1)
>  
[/code]

この例があまり現実的ではないので、確かにこのような関数は定義しないでしょう。

# `Maybe`における「チグハグな関数」例

実際のところ、仰るような「チグハグな関数」は現実世界にはたくさんあります。  
典型的なのは[containersパッケージの`Data.Map.Strict`モジュール、`lookup`関数](http://hackage.haskell.org/package/containers-0.6.3.1/docs/Data-
Map-Strict.html#v:lookup)です。

この関数は、`Map`型という連想配列（RubyでHashと呼ばれるものに相当します。SwiftではDictionaryと呼ぶみたいですね）の型に対して、指定したキーに対応する値を返します。SwiftやRubyで言うところの`some_hash[key]`に相当する関数です。  
（具体例は長くなるので後ろに追記しました）

[code]

    lookup :: Ord k => k -> Map k a -> Maybe a 
    
[/code]

このとき、`lookup`の結果はキーに対応する値が入っていない可能性があるので、値が入っていないかも知れない（だから事前にチェックする必要がある）`Maybe
a`という文脈を持った値になります。  
一方、`lookup`の引数、つまりキーや検索する`Map`そのものは基本的に所与のものであるはずで、`lookup`がキーや`Map`自体の存在をチェックするのは、煩雑でしょう。それは`lookup`に引数を渡す側の責務です。

このようにして、引数と戻り値で文脈が異なる関数ができあがります。

# `IO`における「チグハグな関数」例

それから、すでにお使いであろう`putStrLn`関数も`String -> IO ()`という型なので、恐らく仰る「チグハグな関数」に該当するはずです。  
`IO`における「文脈」とは、「`IO`アクションを実行して、結果となる値を取得すること」に該当します。  
仮に`putStrLn`が`IO String -> IO
()`という、同じ文脈をそのまま使い回すような型であった場合、`putStrLn`が引数として受け取った`IO`アクションを実行しなければならなくなります。本来やりたいことは文字列を表示することなのに、余計な`IO`アクションを実行してしまうわけです。  
なので、`putStrLn`が欲しいのは単なる、`IO`という文脈を持たない`String`なのです。

※`IO`の例えはちょっとわかりづらいかも知れません。そもそも`IO`アクションってなんなの？ということが気になったら[IO
モナドと副作用](https://haskell.jp/blog/posts/2020/io-monad-and-
sideeffect.html)や、手前味噌で恐縮ですが[HaskellのIOは他の言語でいうところの関数オブジェクトとよく似てるよ、という話](https://the.igreque.info/posts/2017/01-haskell-
io-in-java.html)をご覧ください。

# そもそも「文脈」とは

ちなみに、Monadで言うところの「文脈」というのはここまで説明したとおり、

  * `Maybe`で言えば「値が入っているかどうか事前にチェックすること」
  * `IO`で言えば「値を取り出すために事前に実行すること」

といった具合に、「他の関数に値を渡す **前に** やらなければならない操作」と考えると、しっくりくるのではないかと思います。  
これは、具体的に言えば各種`Monad`のインスタンスにおける`>>=`の定義がそのまま相当しますし、`do`記法で言えば

[code]

    do
      result <- action1
      action2 result
      action3
    
[/code]

の、各`action`の「間」でやっていることに相当します。  
まさにアクションとアクションの「間」にあるものが「文脈」なのです。

# 追記: `>>=` の使用例

お待たせしております。ちょっと長くなってしまいましたが例を書きました。詳細はソースのコメントをご覧ください。

ここで使用している`Maybe`に対する`>>=`を`case`式に変えたり、`do`における`<-`を`>>=`に変えてみると、それぞれのありがたみがよくわかるのではないかと思います。  
（ **変え方についてわからないことがあればまた別に質問してください** ）  
また、解説が不十分だと感じたらコメントをください。

[code]

    import           Data.Maybe (listToMaybe)
    import           System.Environment (getArgs)
    import qualified Data.Map.Strict as M
    
    -- コマンドライン引数として受け取ったユーザー名から、
    -- ユーザーのお気に入りを取り出すプログラム
    
    -- | ユーザーの名前をキー、ユーザーのIDを値としたRDBのテーブルもどき
    userByName :: M.Map String Int
    userByName = M.fromList
      [ ("foo", 1)
      , ("bar", 2)
      , ("baz", 3)
      ]
    
    
    -- | ユーザーのIDをキー、ユーザーのお気に入りを値としたRDBのテーブルもどき
    favoritesById :: M.Map Int String
    favoritesById = M.fromList
      [ (1, "ice cream")
      , (3, "ramen")
      ]
    
    
    main :: IO ()
    main = do
      -- 一つ目の >>= を使っている例。
      -- getArgs :: IO [String] という型なので、コマンドライン引数を取り出すアクションを実行して
      -- 何でもない普通の[String]を取得する
      args <- getArgs
      let mFavorites :: Maybe String
          mFavorites = do
            -- 二つ目の >>= を使っている例
            -- listToMaybeでコマンドライン引数の先頭の要素を取り出して、
            -- Maybe Stringじゃない、ただのStringを取得する
            name <- listToMaybe args
            findFavoritesByName name
      print mFavorites
    
    
    -- | 三つ目の >>= を使っている例。
    --   RDBのJOINをするような要領で、
    --   ユーザーの名前からユーザーのお気に入りを取得する
    --   どちらかのテーブルに対応する値がなければ
    --   直ちにNothingが返る
    findFavoritesByName :: String -> Maybe String
    findFavoritesByName name = do
      userId <- M.lookup name userByName
      M.lookup userId favoritesById
    
[/code]


CC BY-SA 4.0
2020-09-01T13:14:36.510
70052
2020-09-02T00:42:28.647
2020-09-02T00:42:28.647
8007
8007
70051
answer


おそらくモナドの良さを分かっていただければこの「ちぐはぐ」を理解いただけると考えたので、その説明をしてみます。

`>>=`、あるいは `bind` とも呼ばれるこの関数には色々と良い性質があるのですが、こと「プログラムをシンプルに書きたい」という側面から見ると、do
記法（do notation）と呼ばれる略記法と一緒に使うことで真価を発揮します。

`Maybe Int` 型の値を受け取り、もし `Just x` が入っていれば `Just (x + 1)`
を返す関数を実装することを考えてみましょう。この関数はパターンマッチを使うことで以下のように書けます。

[code]

    incMaybe :: Maybe Int -> Maybe Int
    incMaybe Nothing = Nothing
    incMaybe (Just x) = Just (x + 1)
    
[/code]

この関数では、`Nothing` なら `Nothing`、`Just` なら中身を取り出して演算した上で再度 `Just`
で包む、ということをしています。`Maybe` 型を使った処理を書くときには良く出てくるパターンです。

この関数は `>>= :: Maybe a -> (a -> Maybe b) -> Maybe b` と `return :: a -> Maybe a`
を使って以下のように書くこともできます。型をよく見て、これで良いことを確認してみてください。たとえば `Nothing` を与えたら `Nothing`
が返ってくるでしょうか。`Just 42` を与えたら `Just 43` が返ってくるでしょうか。

[code]

    incMaybe :: Maybe Int -> Maybe Int
    incMaybe x = x >>= (\y -> return (y + 1))
    
[/code]

さて、`>>=` を使った実装だと、さっきまであったパターンマッチはどこに消えてしまったのでしょうか。実はさっきまで存在していたパターンマッチの部分を
`>>=` が担ってくれています。そもそも `Maybe` モナドの `>>=` はたとえば次のように実装されるのでした。

[code]

    (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
    Nothing >>= _ = Nothing
    (Just x) >>= f = f x
    
[/code]

これが `>>=` の便利なところです。`Maybe` という「値がある
"かもしれない"」という計算を上手く処理してくれるのです。これがちゃんとできるということを確かめるにはモナド則というルールを確認することになるのですが、ここでは詳細には立ち入らぬこととします。

ところで、この `>>=` を使った実装はいささか大変です。たかが +1
するためのことに記号が乱立しています。そこで、もっと簡単に実装するために出てくるのが do 記法です。do
記法を使うと上と同じことをする関数を以下のとおり書くことができます。

[code]

    incMaybe :: Maybe Int -> Maybe Int
    incMaybe x = do
      y <- x
      return (y + 1)
    
[/code]

詳しくは別途調べていただきたいのですが、これは先ほどの `>>=` を使った実装と同じ挙動を表しています（構文糖衣になっています）。`Nothing` と
`Just x` の取り扱いをモナドの側に任せ、コアとなるロジックの部分だけを書けるのがお分かりかと思います。

もう少し複雑な例を見て見ましょう。`Maybe Int` をふたつ受け取って、足して `Maybe Int` を返す関数です。

[code]

    plusMaybe :: Maybe Int -> Maybe Int -> Maybe Int
    plusMaybe x y = do
      a <- x
      b <- y
      return (a + b)
    
[/code]

この関数はふたつの引数のどちらかが `Nothing` であれば `Nothing` を返し、どちらも `Just x` の形であれば中身を足して
`Just x` の形で返します。「中身を足す」というロジックになるべく注目して関数の中身を書けています。

このように `>>=` または `do` を使って書いていくことによって上手く計算を分離し、シンプルに書けるというのが `>>=`
の良さのひとつです。質問文中に引用されている文章から採用して言い換えると、「外と中を分離するための仕組み」のための道具のひとつが `>>=` なのです。

* * *

余談：`incMaybe` はこう書くこともできます。`(+ 1)` というのは `\x -> x + 1` とほぼ同じ意味です。

[code]

    incMaybe :: Maybe Int -> Maybe Int
    incMaybe = fmap (+ 1)
    
[/code]

`>>=` で必要とされていたのは `Int -> Maybe Int` な関数ですが、`fmap` では `Int -> Int`
な関数を使って実現できます。

一方、`plusMaybe` くらいになってくると `Int -> Maybe Int`
な関数を使って処理を繋げていく書き方も便利そうなのがなんとなく感じられるのではないかなあ……と思っています。


CC BY-SA 4.0
2020-09-01T23:26:05.197
70060
2020-09-02T00:23:19.433
2020-09-02T00:23:19.433
19110
19110
70051
answer