モナド整理

※初歩的な部分

### Functor
※復習  [Functor整理](https://qiita.com/KimKo/items/f3d75081495f465ed171)

何かを写すモノという概念を型クラスとして定義したモノ。
```haskell
fmap :: Functor f => (a -> b) -> f a -> f b
```
という関数で、f a を f b へと変換（写す）している。
```haskell
ghci> fmap (\x -> x + 1) (Just 1) -- Just 2
ghci> fmap (\x -> x + 1) [1,2] -- [2,3]
```
MaybeもリストもFunctorのinstance

### Applicative Functor
※復習  [Applicative Functor 整理](https://qiita.com/KimKo/items/0165bd760a9b1b429752)

Functorの拡張版。できることが多いFunctor。
```haskell
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b

--- Controll.Applicative
(<$>) :: Functor f => (a -> b) -> f a -> f b
f <$> x = fmap f x
```
上記関数をもっていて、関数にもFunctorの文脈を付けられる。※ここのfは型コンストラクタFunctor
```haskell
ghci> pure (+) <*> Just 3 <*> Just 3 -- Just 6
ghci> (+) <$> Just 3 <*> Just 3 -- Just 6
```

### モナド整理
Applicative Functorの拡張版。要するにFunctorってざっくり理解。

#### できること
「なんらかの文脈付きa」 と 「純粋なaから文脈付きbを作る関数」をうけとって、「文脈つきb」を作り出す 。
```haskell
m a -> (a -> m b) -> m b -- m Monad
```
(a -> m b)という関数が先にあって、(m a)をこの関数に適応させたい時に使える。
<br>

```haskell
type Monad :: (* -> *) -> Constraint
class Applicative m => Monad m where
  (>>=) :: m a -> (a -> m b) -> m b
  (>>) :: m a -> m b -> m b
  return :: a -> m a
```
できること に書いた変換は (>>=) で行える。

<br>

```haskell
instance Monad Maybe where
    return         = Just
    fail           = Nothing -- これはシステムからCallされる。
    Nothing  >>= f = Nothing
    (Just x) >>= f = f x
```
Maybe は Monad。できること の動きが可能となっている。

```haskell
ghci> Just 9 >>= \x -> return (x + 10)
Just 19
ghci> Nothing >>=  \x -> return (x + 10)
Nothing
```

MonadはFunctorなので、fmap も <*> もMonad関数でできる。
```haskell
-- f は Functor , m は Monad
fmap :: (a -> b) -> f a -> f b -- functorの関数
(<*>) :: f (a -> b) -> f a -> f b -- applicative functorの関数
(>>=) :: m a -> (a -> m b) -> m b -- monad の関数

-- Functor の fmap は MonadのLiftMで同じことができる
ghci> liftM (+2) (Just 8)
Just 10
ghci> fmap (+2) (Just 8)
Just 10

-- Applicative の <*> は Monadのapで同じことができる
ghci> Just (+2) `ap` Just 8
Just 10
ghci> Just (+2) <*> Just 8
Just 10
```

#### 何に役立つのか
以下のようなパターンマッチが、モナドの文脈(a -> m b)に処理を任せられるので、不要になる。
```haskell
case ... of
  Nothing -> Nothing
  Just x  -> case ... of
               Nothing -> Nothing
               Just y  -> ...
```

たとえば + と - の演算ができる逆ポーランド記法計算機を普通に実装するとこんな感じ
```haskell
-- input : "12+2-" ans 1
resolveRPN :: String -> Double
resolveRPN st = head $ foldl foldingFunc [] (words st)
    where   foldingFunc (x:y:ys) "+" = (x+y):ys
            foldingFunc (x:y:ys) "-" = (x-y):ys
            foldingFunc xs number = read number:xs
```
これに失敗するかも という文脈を与えたい
```haskell
monadRPN :: String -> Maybe Double
```

畳み込みに使用する補助関数の出口をMaybeに変更
```haskell
-- String -> Intへの変換をMaybeで扱う
readMaybe :: (Read a) => String -> Maybe a
readMaybe st = case reads st of [(x, "")] -> Just x
                                _ -> Nothing
-- 畳み込み関数にもMaybeを扱う
foldingFunc :: [Double] -> String -> Maybe [Double]
foldingFunc (x:y:ys) "+" = Just ((x+y):ys)
foldingFunc (x:y:ys) "-" = Just ((x-y):ys)
foldingFunc (x:y:ys) "*" = Just ((x-y):ys)
foldingFunc xs number = liftM (:xs) (readMaybe number)
```

失敗の文脈を与えたRPN
```haskell
-- Maybe [Double] のリスト内が一つの結果になっているかを確認する
checkSize :: [Double] -> Maybe Double
checkSize [result] = return result
checkSize _ = Nothing

monadRPN :: String -> Maybe Double
monadRPN st = foldM foldingFunc [] (words st) >>= checkSize

monadRPN "1 2 * 4 +"  -- Just 6.0
monadRPN "1 2 * 4 + 5 *"  -- Just 30.0
monadRPN "1 2 * 4" -- Nothing
monadRPN "1 8 jifa"  --  Nothing
```

checkSizeはDo記法を使うと省略可能
```haskell
monadRPN st = do
    [result] <- foldM foldingFunc [] (words st)
    return result
```

いまのMaybe値がNothingなのかJustなのか、と言った関心を持つ必要がないのが利点



**補足**
他、
リストもモナドだが、モノイドあたりから解説書きたいので別記事でやるかも（Maybe）