RubyのProcでのCurry化、部分適用(partial application)など

# はじめに
Rubyでは、`each`や`map`などを使う時、下記のような書き方があります。

```rb
strs = %w(1000 1001 1010)
strs.map do |s|
  s.to_i
end
# OR
strs.map{ |s| s.to_i }
# OR
strs.map(&:to_i)
```

しかし、`.to_i(2)`など、要素自身以外の変数を代入しようとする時、`strs.map(&:to_i)`の書き方が書けないのは少し不便でした。

ちょうど最近、私はPythonを触っていて、関数の部分適用(partial application)からヒントを得ました。
例えば上記Rubyの例をPythonにすると

```py
strs = ['1000', '1001', '1010']

import functools
int_bin = functools.partial(int, base=2)

[int_bin(s) for s in strs] # [8, 9, 10]
# Or
list(map(lambda s:int_bin(s), strs))
# Or
list(map(int_bin, strs))
```

上記Pythonコードでは、`int_bin`という`int(s, base=2)`の部分適用を作り出し、レシーバーとして`map`に渡しました。

# `map`に任意のBlockやProcを代入する

下記の方法を使います。
解説は[こちらの記事](https://qiita.com/kasei-san/items/0392097791d3a5998216)を読んでください。

```rb
# Proc を使う場合
to_i_bin = ->(s, base=2) { s.to_i(base) }

strs = %w(1000 1001 1010)
strs.map(&to_i_bin)
# [8, 9, 10]
```

```rb
# def を使う場合
def to_i_bin(s, base=2)
  s.to_i(base)
end

strs = %w(1000 1001 1010)
strs.map(&method(:to_i_bin))
# => [8, 9, 10]
```

## 他モジュール内メソッドを使いたい場合
[こちらの記事](https://bugs.ruby-lang.org/issues/16113)を参考してください。

```rb
strs = %w(1000 1001 1010)
strs.map(&JSON.method(:parse))
# [1000, 1001, 1010]

# Ruby 2.7 以上
strs.map(&JSON.:parse)
```

# カリー(Curry)化関数を`map`に渡す

## `foo.bar()` を `bar(foo)` へ

JavaScript界隈でよく使われるトリックの一つ、`call`の活用みたいに、Rubyにも類似する使い方があります。

```js
'abc'.toUpperCase(); // "ABC"

// 下記の形式に書き換えられる
''.toUpperCase.call('abc'); // "ABC"
```

Rubyだと

```rb
'abc'.upcase # "ABC"

# 下記の形式に書き換えられる
:upcase.to_proc.call('abc')
# => "ABC"

# callの簡略形式も可
:upcase.to_proc.('abc')
# => "ABC"
:upcase.to_proc['abc']
# => "ABC"
```

## Curry化
RubyはPythonみたいに`functools.partial`のような関数が組み込まれていない(単純に私の不勉強であるかもしれませんが)ですが、`Method#curry`や`Proc#curry`を活用すれば、想定の効果が得られます。

```rb
to_i_c = :to_i.to_proc.curry(2)

to_i_c.call('1001').call(2)
# => 9

# Or
to_i_c['1001'][2]
# => 9
```

## Curry化メソッドの代入

上記Curry化メソッドを`map`に代入してみます

```rb
to_i_c = :to_i.to_proc.curry(2)

[2, 8, 10].map(&to_i_c['1001'])
# => [9, 513, 1001]
```

なぜそうなっているかは、`map`でカリー化メソッドを呼び出しつづ、レシーバーにする時、最後の引数だけがiterationの対象となっていて、つまり上記のロジックを展開するとこうなります。

```rb
[2, 8, 10].map do |i|
  to_i_c['1001'][i]
end
```

もし、中間の引数をiterationの対象にしたい場合、引数の位置を変更する必要があります。

### 引数の位置を変更

```rb
to_i_r = -> (b, s) { :to_i.to_proc[s, b] }
to_i_c = to_i_r.curry(2)

strs = %w(1000 1001 1010)
strs.map(&to_i_c[2])
# => [8, 9, 10]
```

### 引数をMixinして実行(2019-10-11 Update)
とある親切なRubyのコミッターの方が教えてくれたやり方のアレンジです。

```ruby
curry_exec = -> (f, *args_outer) {
  -> (*args_inner) { f[*args_inner, *args_outer] }
}.curry

%w(1000 1001 1010).map(&curry_exec[:to_i.to_proc, 2])
# => [8, 9, 10]
```

結局、特別な必要がなければ、大人しくProcかBlockを書くほうが、シンプルですね。

```rb
strs = %w(1000 1001 1010)

strs.map{ |s| s.to_i(2) }
# Or
strs.map(&->(s){ s.to_i(2) })
```


# 参考
- [なぜRubyでブロック付き引数を持つメソッドの引数として&:upcaseみたいな値を渡せるのか](https://blog.mah-lab.com/2014/05/19/ruby-block-proc-arguments/)
- [&演算子と、procと、Object#method について理解しなおす](https://qiita.com/kasei-san/items/0392097791d3a5998216)
- [Rubyのmethodをlambdaに変換する](https://qiita.com/junsumida/items/9c7375347ea311e467ef)
- [Ruby block/proc/lambdaの使いどころ](https://qiita.com/kidach1/items/15cfee9ec66804c3afd2)
- [Rubyの ブロック、Proc.new、lambdaの違い](https://qiita.com/ryo-ma/items/24c46592b45775e8644d)
- [Procのカリー化と部分適用](https://qiita.com/jnchito/items/d704838aed7ce5bff53b)
- [instance method Method#curry](https://docs.ruby-lang.org/ja/latest/method/Method/i/curry.html)
- [Partial application in Ruby](https://www.morozov.is/2019/01/11/partial-application-in-ruby.html)
- [Partial function application](https://rosettacode.org/wiki/Partial_function_application#Ruby)
- [What is the difference between currying and partial application?](https://stackoverflow.com/a/51253347)