If/Then/Maybe 〜条件分岐を Maybe で書き換える〜

未来から来た[ジョン・タイター](https://ja.m.wikipedia.org/wiki/ジョン・タイター)は次のように述べたらしい。

> プログラミングの主流が、「If/Then」方式から「If/Then/Maybe」方式へと変わっている

よろしい、ならば条件分岐を Haskell の`Maybe`で書き換えてやる！（ネタです）


# If/Then/Else

次の条件分岐は

```.hs
if flg then v1 else v2
```

下記のように書き換えられる。

```.hs
guard flg $> v1 & fromMaybe v2
```

なお、全部 import が必要😇

```.hs
import Control.Monad (guard)
import Data.Functor (($>))
import Data.Function ((&))
import Data.Maybe (fromMaybe)
```

## 仕組み

### guard

[guard の定義](https://hackage.haskell.org/package/base-4.12.0.0/docs/Control-Monad.html#v:guard)は次の通りだが、

```.hs
guard :: (Alternative f) => Bool -> f ()
guard True  =  pure ()
guard False =  empty
```

`Maybe`の場合、必要な定義だけ参照すると

```.hs
instance Applicative Maybe where
    pure = Just
    
instance Alternative Maybe where
    empty = Nothing
```

である。結局、`Maybe`に特殊化した`guard`は次のように**動作**する。

```.hs
guard :: Bool -> Maybe ()
guard True  = Just ()
guard False = Nothing
```

### $>

`$>`の必要な定義を抜き出すと次のようになる。

* [$>](https://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Functor.html#v:-36--62-)
* [flip](https://hackage.haskell.org/package/base-4.12.0.0/docs/Prelude.html#v:flip)
* [Functor](https://hackage.haskell.org/package/base-4.12.0.0/docs/Prelude.html#t:Functor)
* [.](https://hackage.haskell.org/package/base-4.12.0.0/docs/Prelude.html#v:.)
* [const](https://hackage.haskell.org/package/base-4.12.0.0/docs/Prelude.html#v:const)

```.hs
($>) :: Functor f => f a -> b -> f b
($>) = flip (<$)

flip :: (a -> b -> c) -> b -> a -> c
flip f x y = f y x

class Functor f where
    (<$) :: a -> f b -> f a
    (<$) = fmap . const

    fmap :: (a -> b) -> f a -> f b

(.) :: (b -> c) -> (a -> b) -> a -> c
(.) f g = \x -> f (g x)

const :: a -> b -> a
const x _ = x
```

以上より、次のように展開できる。つまり、`$>`は既存の中身`a`を捨てて、新規の中身`b`に入れ替えるための演算子を意味する。

```.hs
  fa $> b
= flip (<$) fa b      -- $> の定義
= b <$ fa             -- flip の定義
= (fmap . const) b fa -- <$ の定義
= (\x -> fmap (const x)) b fa -- . の定義
= fmap (const b) fa   -- 関数適用
= fmap (\_ -> b) fa   -- constの定義と部分適用
```

`Maybe`の場合、

```.hs
instance Functor Maybe where
    fmap _ Nothing  = Nothing
    fmap f (Just a) = Just (f a)
```

だから、`Maybe`に特殊化した`$>`は次のように**動作**する。

```.hs
($>) :: Maybe a -> b -> Maybe b
Just _  $> x = Just x
Nothing $> _ = Nothing
```

### &

[&の**定義**](https://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Function.html#v:-38-)は次の通り。

```.hs
(&) :: a -> (a -> b) -> b
x & f = f x
```

### fromMaybe

[fromMaybeの定義](https://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Maybe.html#v:fromMaybe)は次の通り。

```.hs
fromMaybe :: a -> Maybe a -> a
fromMaybe d x = case x of {Nothing -> d; Just v -> v}
```

次のように見やすくしても同じ**動作**になる。

```.hs
fromMaybe :: a -> Maybe a -> a
fromMaybe _ (Just v) = v
fromMaybe d Nothing  = d
```

### flg == True の場合

```.hs
  guard flg $> v1 & fromMaybe v2
= guard True $> v1 & fromMaybe v2 --仮定より
= Just () $> v1 & fromMaybe v2 --guardの動作
= Just v1 & fromMaybe v2 -- $> の動作
= fromMaybe v2 (Just v1) -- & の定義
= v1                     -- fromMaybe の動作
```


### flg == False の場合

```.hs
  guard flg $> v1 & fromMaybe v2
= guard False $> v1 & fromMaybe v2 --仮定より
= Nothing $> v1 & fromMaybe v2 --guardの動作
= Nothing & fromMaybe v2 -- $> の動作
= fromMaybe v2 Nothing   -- & の定義
= v2                     -- fromMaybe の動作
```

### 結論

以上より、次式が成り立つ。

```.hs
  guard flg $> v1 & fromMaybe v2
= if flg then v1 else v2
```



# If/Then

余談だが、他の言語だと`if(flg) return v;`のように`else`の省略された早期リターン（ガード節）を書くことがある。ただ、Haskell では`else`を省略できない。代わりに何も返さないことを`Nothing`で表現してみると、次のようになる。

```.hs
if flg then Just v else Nothing
```

上記の条件分岐は If/Then/Else での考察を踏まえると、下記のように書き換えられる。

```.hs
guard flg $> v
```