JavaScriptのカリー化について

# 初めに
もともと`this`のこと調べる途中で現れた、
ある書き方です。
```jsx
const addCurry =(a) => {
    return (b)=>{
        return (c)=>{
            return a+b+c
        }
    }
}
console.log(addCurry(2)(3)(5)) // 10
```
えっ何で引数のあとにまた別の引数が？
`addCurry(2, 3, 5)`ではなく`addCurry(2)(3)(5)`で動けるの？
（早速真似して動かせてみた）動け..た！？
何この書き方、はじめて見た！（新大陸発見した気分です）

そして何日かいろんな参考文章をかみ砕いて、`Currying`が利用している`Closure`がまだはっきり分かっていないので一緒にまとめてみました。
こちらです↓
[JavaScriptのクロージャについて](https://qiita.com/hu-yu/items/4e1c6253c85d1093e1d4)

そして今回はカリー化の理解をまとめていきたいと思います！
参考文章はこちらです↓
[Understanding JavaScript currying](https://blog.logrocket.com/understanding-javascript-currying/#:~:text=What%20is%20currying%20in%20JavaScript,functions%20with%20a%20single%20argument.)
[Closures and currying](https://fbuireu.medium.com/closures-and-currying-9774676d33fa#:~:text=Currying%20means%20that%20the%20closure,other%20arguments%20as%20you%20go.)

# JavaScriptの`Currying`とは
自分の理解で言いますと、いままでのように一回性で必要な引数を入れるのではなく、あらかじめ関数の引数を数段階に分けて、段階別に引数を自由に操作できる考え方です。
例えば参考文章の例のように、
```jsx: Noncurried version
const add = (a, b, c) => {
  return a + b + c
}
console.log(add(2, 3, 5)) // 10
```
これはすべての引数を一回で入れるやり方で、もし最後`c`の引数を修正しようとしたら、`a`も`b`ももう一度引数入れなければなりません。
しかしカリー化した関数は、
```jsx: Curried version
const addCurry = (a) => {
  return (b) => {
    return (c) => {
      return a + b + c
    }
  }
}
console.log(addCurry(2)(3)(5)) // 10
```
えっ何か書き方だけ変わったけど結果は変わってないんじゃない？
お気持ち痛いほどわかります！しかし`Currying`が理解できたら見方全然変わってきますよ。
説明する前にちょっとほかの例を見ていきたいと思います。
まずは上の例をこう書いたらどうなるでしょう？
```jsx
const addCurry = (a) => {
  return (b) => {
    return (c) => {
      return a + b + c
    }
  }
}
// console.log(addCurry(2)(3)(5)) // 10

const addFirstArgument = addCurry(2)
console.log(addFirstArgument(3)(5)) // 10
const addSecondArgument = addFirstArgument(3)
console.log(addSecondArgument(5)) // 10
```
相変わらず引数が三つが必要だけど、変数に入れることによって毎回入れる引数が減っていくんです。

簡単にいうと`Currying`は、
変数`addFirstArgument`と`addSecondArgument`のように`addCurry(2)`関数の戻り値を入れることによって、`Closure`の特性の利用して全部の引数を満たすまで値をキープしている。（引数入れるときの順番に注意）

# いろいろ応用してみた
ここから参考文章の例を用いて少し改造し応用してみました。
（ランダムに挨拶するプログラム？）
```jsx: Basic curring example
const obj = {
  greeting: ['Hi', 'Hello', 'Hey'],
  guest: ['Mary', 'Mick', 'Lucy', 'Daisy'],
  message: 'Welcome to the internet!'
}

const greetings = obj.greeting
const guests = obj.guest

function radom(range) {
  return Math.floor(Math.random() * range)
}

// function Welcome(greet) {
//   return function (name) {
//     return function (message) {
//       return `${greet} ${name}, ${message}`
//     }
//   }
// }

// Modern currying with ES6
const Welcome = greet => name => message =>
  `${greet} ${name} ${message}`

// console.log(Welcome(greetings[radom(greetings.length)])(guests[radom(guests.length)])(obj.message))

const sendGreet = Welcome(greetings[radom(greetings.length)])
const sendName = sendGreet(guests[radom(guests.length)])
const sendMessage = sendName(obj.message)
console.log(sendMessage)
```
ここは必要なデータが全部`obj`から抽出したけど、ほかのDBやAPIを使ったり好きな段階（引数の順番）にデータを埋め込みしたり、さらに自由度が上がると思います。

# `Currying` vs. `Partial application`
わざわざ`Currying`を書かなくても、`Partial application`ってやり方ではもっと直感的に分かりやすくなるのでは？
私もそう思いました。でもやっぱり、やっぱり違います...
ちょっと例を見てみましょう。
```jsx: Currying vs. partial application
const addPartial = (x, y, z) => {
  console.log(x, y, z)
  return x + y + z
}

const partialFunc = addPartial.bind(this, 2, 3)
console.log(partialFunc())
// 2 3 undefined
// NaN
console.log(partialFunc(5))
// 2 3 5
// 10
```
簡単に言うと、`Partial application`では、絶対ではないけどよく`bind()`などのバインドメソッドを使って強制的に`this`のコンテキストを変えて、**新しい関数**を返すことになる。（**function borrowing**）

`Currying`が求める一回に一つの引数のやり方と違って、`Partial application`はコンテキストを変えることで、別の方向にできることが増えました。

必ずしもどれを使ったほうがいいのではなく、使い分けが大事だと思います。

# `Currying`おまけの検証コード
```jsx
const add = function (x) {
  console.log(x)
  return function (y) {
    console.log(x, y)
    return x + y
  }
}

let increment = add(1)
let addTen = add(10)

console.log(increment(2)) // 3
console.log(addTen(2)) // 12

// 1 // increment = add(1), log x
// 10 // addTen = add(10), log x

// 1 2 // increment(2), log x, y
// 3 // increment(2), log x + y

// 10 2 // addTen(2), log x, y
// 12 // addTen(2), log x + y

// note: 'add' accepts one params and return function
// note: return value will save in the closure and keep 'add's first params

// compare
console.log(add(1)(2)) // 3
console.log(add(10)(2)) // 12

// 1 // add(1)(2), log x
// 1 2 // add(1)(2), log x, y
// 3 // add(1)(2), log x + y

// 10 // add(10)(2), log x
// 10 2 // add(10)(2), log x, y
// 12 // add(10)(2), log x + y
```