[Haskell] Either a c -> Either b d の変換

# 0. まとめ

用途別:

- `(b -> c) -> Either a b -> Either a c`
    - `(<$>)`
    - `(<$)`, `($>)`
    - `right`
    - `second`
- `(a -> b) -> Either a c -> Either b c`
    - `left`
    - `first`
- `(a -> b) -> (c -> d) -> Either a c -> Either b d`
    - `(+++)`
    - `bimap`
- `(b -> Either a c) -> Either a b -> Either a c`
    - `(=<<)`, `(>>=)`
    - `do` 記法の `<-`
- `(a -> Either b c) -> Either a c -> Either b c`
    - `either`
    - `(|||)`
- `(a -> Either b d) -> (c -> Either b d) -> Either a c -> Either b d`
    - `either`
    - `(|||)`

型クラス制約別:

- `Functor`
    - `(<$>)`
    - `(<$)`, `($>)`
- `Monad`
    - `(=<<)`, `(>>=)`
    - `do` 記法の `<-`
- `ArrowChoice`
    - `left`
    - `right`
    - `(+++)`
    - `(|||)`
- `Bifunctor`
    - `first`
    - `second`
    - `bimap`

参考「[(<$>) - Data.Functor](https://hackage.haskell.org/package/base-4.19.0.0/docs/Data-Functor.html#v:-60--36--62-)」
参考「[(<$) - Data.Functor](https://hackage.haskell.org/package/base-4.19.0.0/docs/Data-Functor.html#v:-60--36-)」
参考「[($>) - Data.Functor](https://hackage.haskell.org/package/base-4.19.0.0/docs/Data-Functor.html#v:-36--62-)」

参考「[(=<<) - Control.Monad](https://hackage.haskell.org/package/base-4.19.0.0/docs/Control-Monad.html#v:-61--60--60-)」
参考「[(>>=) - Control.Monad](https://hackage.haskell.org/package/base-4.19.0.0/docs/Control-Monad.html#v:-62--62--61-)」

参考「[left - Control.Arrow](https://hackage.haskell.org/package/base-4.19.0.0/docs/Control-Arrow.html#v:left)」
参考「[right - Control.Arrow](https://hackage.haskell.org/package/base-4.19.0.0/docs/Control-Arrow.html#v:right)」
参考「[(+++) - Control.Arrow](https://hackage.haskell.org/package/base-4.19.0.0/docs/Control-Arrow.html#v:-43--43--43-)」
参考「[(|||) - Control.Arrow](https://hackage.haskell.org/package/base-4.19.0.0/docs/Control-Arrow.html#v:-124--124--124-)」

参考「[first - Data.Bifunctor](https://hackage.haskell.org/package/base-4.19.0.0/docs/Data-Bifunctor.html#v:first)」
参考「[second - Data.Bifunctor](https://hackage.haskell.org/package/base-4.19.0.0/docs/Data-Bifunctor.html#v:second)」
参考「[bimap - Data.Bifunctor](https://hackage.haskell.org/package/base-4.19.0.0/docs/Data-Bifunctor.html#v:bimap)」

参考「[either - Data.Either](https://hackage.haskell.org/package/base-4.19.0.0/docs/Data-Either.html#v:either)」

参考「[[Haskell] モナド 演算子 まとめ - Qiita](https://qiita.com/kerupani129/items/333155e5e2dee644d6dc)」

# 1. `Right` 同士および `Left` 同士の変換

## 1.1. `Either a b -> Either a c`

`Right` の値のみ変換する場合は演算子 `<$>`、`right` 関数または `second` 関数を用います。

```haskell
import Control.Arrow (right)
import Data.Bifunctor (second)

f :: Int -> String
f = show

main :: IO ()
main = do

    let x  = Right 23 :: Either Int Int
    let x' = Left  42 :: Either Int Int

    do

        let y  = f <$> x  :: Either Int String
        let y' = f <$> x' :: Either Int String

        print y
        print y'

    do

        let y  = right f x  :: Either Int String
        let y' = right f x' :: Either Int String

        print y
        print y'

    do

        let y  = second f x  :: Either Int String
        let y' = second f x' :: Either Int String

        print y
        print y'
```

```text:実行結果
Right "23"
Left 42
Right "23"
Left 42
Right "23"
Left 42
```

`Right` の値のみ置き換える場合は演算子 `<$` または `$>` を用います。

`right` 関数または `second` 関数を用いるやり方もあります。

```haskell
import Control.Arrow (right)
import Data.Bifunctor (second)

main :: IO ()
main = do

    let x  = Right 23 :: Either Int Int
    let x' = Left  42 :: Either Int Int

    do

        let y  = "Foo" <$ x  :: Either Int String
        let y' = "Foo" <$ x' :: Either Int String

        print y
        print y'

    do

        let y  = right (const "Foo") x  :: Either Int String
        let y' = right (const "Foo") x' :: Either Int String

        print y
        print y'

    do

        let y  = second (const "Foo") x  :: Either Int String
        let y' = second (const "Foo") x' :: Either Int String

        print y
        print y'
```

```text:実行結果
Right "Foo"
Left 42
Right "Foo"
Left 42
Right "Foo"
Left 42
```

## 1.2. `Either a c -> Either b c`

`Left` の値のみ変換する場合は `left` 関数または `first` 関数を用います。

```haskell
import Control.Arrow (left)
import Data.Bifunctor (first)

f :: Int -> String
f = show

main :: IO ()
main = do

    let x  = Right 23 :: Either Int Int
    let x' = Left  42 :: Either Int Int

    do

        let y  = left f x  :: Either String Int
        let y' = left f x' :: Either String Int

        print y
        print y'

    do

        let y  = first f x  :: Either String Int
        let y' = first f x' :: Either String Int

        print y
        print y'
```

```text:実行結果
Right 23
Left "42"
Right 23
Left "42"
```

`Left` の値のみを置き換える場合も同様です。

```haskell
import Control.Arrow (left)
import Data.Bifunctor (first)

main :: IO ()
main = do

    let x  = Right 23 :: Either Int Int
    let x' = Left  42 :: Either Int Int

    do

        let y  = left (const "Foo") x  :: Either String Int
        let y' = left (const "Foo") x' :: Either String Int

        print y
        print y'

    do

        let y  = first (const "Foo") x  :: Either String Int
        let y' = first (const "Foo") x' :: Either String Int

        print y
        print y'
```

```text:実行結果
Right 23
Left "Foo"
Right 23
Left "Foo"
```

## 1.3. `Either a c -> Either b d`

`Right` と `Left` の両方の値を変換する場合は演算子 `+++` または `bimap` 関数を用います。

```haskell
import Control.Arrow ((+++))
import Data.Bifunctor (bimap)

f :: Int -> String
f = show

g :: Int -> String
g = show

main :: IO ()
main = do

    let x  = Right 23 :: Either Int Int
    let x' = Left  42 :: Either Int Int

    do

        let y  = (g +++ f) x  :: Either String String
        let y' = (g +++ f) x' :: Either String String

        print y
        print y'

    do

        let y  = bimap g f x  :: Either String String
        let y' = bimap g f x' :: Either String String

        print y
        print y'
```

```text:実行結果
Right "23"
Left "42"
Right "23"
Left "42"
```

`Right` と `Left` の両方の値を置き換える場合も同様です。

```haskell
import Control.Arrow ((+++))
import Data.Bifunctor (bimap)

main :: IO ()
main = do

    let x  = Right 23 :: Either Int Int
    let x' = Left  42 :: Either Int Int

    do

        let y  = (const "Bar" +++ const "Foo") x  :: Either String String
        let y' = (const "Bar" +++ const "Foo") x' :: Either String String

        print y
        print y'

    do

        let y  = bimap (const "Bar") (const "Foo") x  :: Either String String
        let y' = bimap (const "Bar") (const "Foo") x' :: Either String String

        print y
        print y'
```

```text:実行結果
Right "Foo"
Left "Bar"
Right "Foo"
Left "Bar"
```

# 2. `Right` から `Left` へおよび `Left` から `Right` への変換

## 2.1. `Either a b -> Either a c`

`Right` の値を `Right` または `Left` の値に変換する場合は、演算子 `=<<`, `>>=` または `do` 記法の `<-` を用います。

```haskell
import Control.Monad (when)

f :: Int -> Either Int String
f x = do
    when (x < 0) $ do
        Left x
    Right $ show x

main :: IO ()
main = do

    let x1 = Right    23 :: Either Int Int
    let x2 = Right $ -23 :: Either Int Int
    let x3 = Left     42 :: Either Int Int
    let x4 = Left  $ -42 :: Either Int Int

    do

        let y1 = f =<< x1 :: Either Int String
        let y2 = f =<< x2 :: Either Int String
        let y3 = f =<< x3 :: Either Int String
        let y4 = f =<< x4 :: Either Int String

        print y1
        print y2
        print y3
        print y4

    do

        let y1 = do
                x <- x1
                f x :: Either Int String
        let y2 = do
                x <- x2
                f x :: Either Int String
        let y3 = do
                x <- x3
                f x :: Either Int String
        let y4 = do
                x <- x4
                f x :: Either Int String

        print y1
        print y2
        print y3
        print y4
```

```text:実行結果
Right "23"
Left (-23)
Left 42
Left (-42)
Right "23"
Left (-23)
Left 42
Left (-42)
```

## 2.2. `Either a c -> Either b c`

`Left` の値を `Right` または `Left` の値に変換する関数は標準では提供されないため、`either` 関数または演算子 `|||` を用います。

```haskell
import Control.Arrow ((|||))
import Control.Monad (when)

f :: Int -> Either String Int
f x = do
    when (x < 0) $ do
        Left $ show x
    Right x

main :: IO ()
main = do

    let x1 = Right    23 :: Either Int Int
    let x2 = Right $ -23 :: Either Int Int
    let x3 = Left     42 :: Either Int Int
    let x4 = Left  $ -42 :: Either Int Int

    do

        let y1 = either f Right x1 :: Either String Int
        let y2 = either f Right x2 :: Either String Int
        let y3 = either f Right x3 :: Either String Int
        let y4 = either f Right x4 :: Either String Int

        print y1
        print y2
        print y3
        print y4

    do

        let y1 = (f ||| Right) x1 :: Either String Int
        let y2 = (f ||| Right) x2 :: Either String Int
        let y3 = (f ||| Right) x3 :: Either String Int
        let y4 = (f ||| Right) x4 :: Either String Int

        print y1
        print y2
        print y3
        print y4
```

```text:実行結果
Right 23
Right (-23)
Right 42
Left "-42"
Right 23
Right (-23)
Right 42
Left "-42"
```

## 2.3. `Either a c -> Either b d`

`Right` と `Left` の相互変換をする場合は `either` 関数または演算子 `|||` を用います。

```haskell
import Control.Arrow ((|||))
import Control.Monad (when)

f :: Int -> Either String String
f x = do
    when (x < 0) $ do
        Left $ show x
    Right $ show x

g :: Int -> Either String String
g x = do
    when (x < 0) $ do
        Left $ show x
    Right $ show x

main :: IO ()
main = do

    let x1 = Right    23 :: Either Int Int
    let x2 = Right $ -23 :: Either Int Int
    let x3 = Left     42 :: Either Int Int
    let x4 = Left  $ -42 :: Either Int Int

    do

        let y1 = either g f x1 :: Either String String
        let y2 = either g f x2 :: Either String String
        let y3 = either g f x3 :: Either String String
        let y4 = either g f x4 :: Either String String

        print y1
        print y2
        print y3
        print y4

    do

        let y1 = (g ||| f) x1 :: Either String String
        let y2 = (g ||| f) x2 :: Either String String
        let y3 = (g ||| f) x3 :: Either String String
        let y4 = (g ||| f) x4 :: Either String String

        print y1
        print y2
        print y3
        print y4
```

```text:実行結果
Right "23"
Left "-23"
Right "42"
Left "-42"
Right "23"
Left "-23"
Right "42"
Left "-42"
```