|>(パイプ)と>>(関数合成)の違い(Elm)

#はじめに
こんにちは！

Elmを書いたことのある人なら誰しもパイプ演算子を使って以下のように関数を合成しようとしたことありませんか？ありますよね！（食い気味)　
私はありました！

```elm
initHoge:Hoge
initHoge =
   { stringToBool = stringToInt |> intToBool
   }
 
```
もちろん,こちらはエラーになります。

これはそもそもパイプ演算子(|>)と関数合成(>>)の違いをちゃんと理解していなかったことが原因でした。
なのでこの記事を通して**パイプ演算子と関数合成の違いについてのみなさんの理解が少しでも深まれば！**と思います！

#結論を端的に工場の流れ作業で表すと
関数を**作業員**、
パイプ演算子を**ベルトコンベア**
値を**部品**
に例えると以下のように表せます。(ちゃんと自分で描いてますよ！)

## パイプ演算子
![pipe.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366323/ecfc2bbc-a80b-df49-03d1-2cca4f7c6f4b.png)

## 関数合成
![function_composition.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366323/87bef35c-174d-9485-c23e-6262e22a792b.png)

## 自分が起こしたエラー(パイプで関数を繋げた場合)
![pipe_error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366323/b6b8a5c4-0b39-06f0-8ab9-24e46e07ea5e.png)

もうわかりましたね！！

え？わからない？!


では一体どういうことなのか、自分のした勘違いを紹介しつつ説明します。

#自分のした勘違い

ある日、以下のように関数をフィールドに持つレコード(Hoge)を初期化する関数(initHoge)を作る必要がありました。

※stringToBool はここでは、何かの文字列を受け取って、Bool値を返す関数とします.
また、この時点で**StringをIntにする関数(stringToInt)**、**IntをBoolにする関数(intToBool)**はすでに別の用途で使われて定義されていたとします。

```elm
type alias Hoge =
    { stringToBool : String -> Bool
    }

stringToInt: String -> Int
stringToInt = -- 実装はよしなに

intToBool:Int -> Bool
intToBool = -- 実装はよしなに

initHoge:Hoge
initHoge =
   { stringToBool = -- 定義したい
   }
```
**ワイ** :あーはい、はい。なるほどね。
じゃぁ、**StringをIntにする関数(stringToInt)**と**IntをBoolにする関数(intToBool)**を合体させれば楽勝でしょ!
関数をつなげる演算子といえばこれ, **|>(パイプ)** に限りますよ！

```elm
initHoge:Hoge
initHoge =
   { stringToBool = stringToInt |> intToBool
   }
 
```
終わり！　楽勝！！



```
エラー
```
え！どうして？？？

しかしこれを **`>>`** （関数合成)を使って記述すると、


```elm
initHoge:Hoge
initHoge =
   { stringToBool = stringToInt >> intToBool
   }
```
```
エラーなし
```
ばんなそがな！
一体なぜ！！！？？

だって, **`|>`**って普段以下みたいな使われ方をしていて,エラーが起きないじゃん。
これってつまり、**`|> `**で繋がれた `stringToInt |> intToBool `が `String → Bool`な関数を形成していたってことじゃなかったの？？？

```elm
"1" -- (:String)
 |> stringToInt --( String -> Int な関数　実装は省略)
 |> intToBool --( Int -> Bool な関数　実装は省略）
	-- -> True(:Bool)
```


#なぜ|>では関数を合成できないのか

Elmで何かが期待と違う動きをしたら,
とにかく型定義をみる！カタはウソつかない！

##|>の型定義を振り返る
```elm
(|>) : a -> (a -> b) -> b
```

出典: [https://package.elm-lang.org/packages/elm/core/latest/Basics#|](https://package.elm-lang.org/packages/elm/core/latest/Basics#%7C)

**ん？**
**あれ？これって型定義(a→b)の関数に引数aを渡してるだけでは？？**

そう，そもそもパイプは本来関数の後ろに書くべき引数を前に書くことを許容して，
複数の関数を使うときに()の入れ子を避けるために使われる演算子なのだ！(pipeってそういうもんでしょといわれればそう)

```elm
-- |>を使わないとき
func5 (func4 (func3 (func2 (func1 arg)))

-- |>をつかうと以下のようにできる
arg
 |> func1
 |> func2
 |> func3
 |> func4
 |> func5
```

つまり，もし引数の必要な関数同士を`|>`で繋いだら，

**"関数"**と**"その関数を引数に取る関数"**を繋がないと型定義違反になる！

なぜなら `func1|>func2` は `func2 func1` と同じだから! (func2はfunc1を引数に取る関数)

## 今回の自分の定義を見直す

ここで今回の自分の定義がなぜダメだったのか見直す．

自分が行った定義

```elm
stringToBool : String -> Bool
stringToBool = stringToInt |> intToBool
```
`|>`の左辺は `stringToInt : String -> Int`

ここで、もう一度`|>`の型定義を思い出す。

```elm
(|>) : a -> (a -> b) -> b
```
これを踏まえると、


`|>`の右辺、つまり第二引数は**`((String → Int ) → Bool )`** な関数でないと型が合わない．(a == (String → Int )だから)

型で表すとこう．これが`|>`の求めているもの。

```elm
(String -> Int ) -> ((String -> Int ) -> Bool ) -> Bool
```

しかし実際に右辺に渡されているのは**`((String → Int ) → Bool )`** な関数ではなく`intToBool:Int→Bool`

**だから`toBoolean : String -> Bool` の定義として　`stringToInt |> intToBool`は成り立たない。**

以下のようにしたときに同様のエラーが起こらないのは，

```elm
"1" -- (:String)
 |> stringToInt --( String -> Int な関数　実装は省略)
 |> intToBool --( Int -> Bool な関数　実装は省略）
	-- -> True(:Bool)
```

`"1" |> stringToInt |> intToBool` としたときに，左から演算が行われていき，intToBoolの演算が行われるときには`1|> intToBool`となってすでに|>の左辺が関数ではなくIntに変わっているため！

## |>のまとめ

結局のところ，

**|>**は**"その左辺を右辺に引数として渡す演算子"**に過ぎないため，

**"左辺の関数の出力の型"**と**"右辺の関数の入力の型"**が一致していても

左辺が**引数を渡されていないまだ関数の状態のまま**で両者を繋ぐと，

**値を期待する右辺の関数に対して，関数を渡すことになるため型が一致せずエラーになる．**

したがって，**|>で複数の関数の処理を繋ぐ際は引数が必須**であることがわかる．

だから`|>`でも以下のように書けば，複数の関数の処理をまとめた関数を作ることはできる．

```elm
stringToBool : String -> Bool
stringToBool str = 
   str
     |> stringToInt
     |> intToBool
```

え、文字だらけでわからない？
ここで序盤で登場した絵の出番。

関数を**作業員**、
パイプ演算子を**ベルトコンベア**
値を**部品**
とすると
##正常な時
![pipe.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366323/ecfc2bbc-a80b-df49-03d1-2cca4f7c6f4b.png)
##今回自分がやろうとしたこと（エラー)の再掲
![pipe_error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366323/b6b8a5c4-0b39-06f0-8ab9-24e46e07ea5e.png)

ここまでで，なぜ今回`|>`で関数合成をしようとしたときにエラーが起きたのかわかったと思います。

じゃぁ`>>`って要るの？？なにしてんの？となるので以下で`>>`ができることを紹介します。

#>>(関数合成)の役割

まずは型定義から！

## >>の型定義

`>>`の型を見てみる

```elm
(>>) : (a -> b) -> (b -> c) -> a -> c
```

これはつまり，

```elm
(>>) : (a -> b) -> (b -> c) -> (a -> c)
```

ということ！

したがって，`>>`を使うと，

**"左辺の関数の出力の型(b)"**と**"右辺の関数の入力の型(b)"**が一致していれば，

**定義の時点で左辺の関数に引数aが渡されていなくても，処理を繋げて書くことができる**

だから`|>`では以下のように書いていた処理も

```elm
stringToBool : String -> Bool
stringToBool str = 
	str
	 |> stringToInt
	 |> intToBool
```

`>>`なら次のように引数なしで書ける．

```elm
stringToBool : String -> Bool
stringToBool = stringToInt >> intToBool 
```

また文字だけでわかりづらい？
安心してください。ちゃんと絵があります。

##>>のイメージ
![function_composition.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366323/80b425bd-7976-b1bd-564d-ee54ed28b364.png)

「でもあんまり、`>>`って見かけないような。。どこで使えるんだ？」と思ったそこのあなた
いくつかの使い所を紹介します。

## >>の使いどころ

まずは記事の冒頭の例のように引数を渡されることはなく定義だけを要求される場合に，

`>>`ではワンラインで定義ができます。

`|>`であれば　init関数の外側，あるいはletinで`stringToBool` を引数付きで定義しないといけません。

```elm
type alias Sample = {
		stringToBool : String -> Bool
	}

init :Sample
init = {
	stringToBool = stringToInt >> intToBool
}

{-
以下が定義されてる前提
 stringToInt:String -> Int
 intToBool:Int -> Bool
-}
```

そのほかには以下のような記述が

```elm
List.map (\x -> x|> (+) 2 |> String.fromInt) [1,2,3,4] -- ["3","4","5","6"]
```

次のように書けたりします。

```elm
List.map ((+) 2 >> String.fromInt) [1,2,3,4] --["3","4","5","6"]
```

いずれにせよ`|>`で代替可能であり，`>>`でないと実現できない実装というものはなさそうではあります。（もし記事を見た方でこんな使い方もあるよ！という方がいればぜひコメント欄にお願いします！)


#結論: 

##|>と>>の違い

`|>`は引数と関数を繋ぐもの！

`>>`は関数同士を繋いで巨大な関数をつくるもの！

別の言い方をすると、
前者は処理の流れを作るもの，後者は流れの中の処理自体を改造するものであり，そもそも目的が違う．

もし`|>`で`>>`の真似事をするには引数が必要！

## パイプ演算子のイメージ
![pipe.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366323/ecfc2bbc-a80b-df49-03d1-2cca4f7c6f4b.png)

## 関数合成のイメージ
![function_composition.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366323/87bef35c-174d-9485-c23e-6262e22a792b.png)



となります。
ここまで長々とお付き合いありがとうございました。コメント、指摘お待ちしております。

#参考
- [[Elm] 関数合成を理解する](https://qiita.com/aimy-07/items/429e6b1b6ad64bbf0b49)
- [A Short Guide to Function Operators in Elm (|>, <|, >>, <<)](https://harfangk.github.io/2018/01/27/elm-function-operators.html)
- [What does the << operator mean in elm?](https://stackoverflow.com/questions/27441648/what-does-the-operator-mean-in-elm)
- [When to use >> vs |>?](https://www.reddit.com/r/elm/comments/67izmq/when_to_use_vs/)