ブロックなしRubyをやろうとすると関数型プログラ…うーんリストプロセッ、えーと感じ感じ

ブロックなしRubyをやることでRubyを関数型言語、というかLispっぽくやっていくことについて考えてみます。なお筆者はLispあんまり詳しく無く、「リストに対する操作の適用をネストさせてなんかいい感じにするやつ」くらいの認識で言いました、ごめん。

## ブロックなしRuby初級

```rb
xs = %w`akechi kokoro itoh chika ayase ena koshimizu sachiko`
xs.map{|it|it.capitalize}
#=> ["Akechi", "Kokoro", "Itoh", "Chika", "Ayase", "Ena", "Koshimizu", "Sachiko"]
```

この`map`について以下のように書くイディオムをご存知の方は多いかと思います。

```rb
xs.map &:capitalize
```

こうすることで冗長さがかなり軽減されます（かなり）。要素をイテレートし、各要素をレシーバとしてメソッドを呼び出したい、ただそれだけのために`it`を2回書くなんて面倒ですからね。

では次の`map`をブロックを書かずに書き直すとどうなるでしょうか。

```rb
xs = %w`明智小衣 伊藤千佳 綾瀬恵那 輿水幸子`
xs.map{|it|puts it}
```

ワウ

```rb
xs.map &method(:puts) 
```

こうですね。`each`メソッドについては忘れていきましょう。リストへの操作の適用について意識しだした結果`map`しか使えなくなった人がいます。これがリストプロセッシング、Lispの気持ちなのでしょうか。違うと思う。違うのかな、わからん。

では次です。

```rb
xs = (1..10)
xs.map{|it|2 ** it}
#=> [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
```

まずこれ、`**`演算子に見えるものは実のところメソッド呼び出しなので、以下の様に書き直せます。

```rb
xs = (1..10)
xs.map{|it|2.**(it)}
```

ぶわぶわ

```rb
xs.map &2.method(:**)
```

こうですね。

ここで、`method(:puts)`と`2.method(:**)`が何者なのか見てみましょう。

```rb
method(:puts).inspect
#=> "#<Method: Object(Kernel)#puts>"
2.method(:**).inspect
#=> "#<Method: Fixnum#**>"
```

感じ感じ


## ブロックなしRuby中級

さて、いい感じにブロックを葬り去り簡潔でわかりやすいコードにすることができましたね。

ここで、先ほど挙げた3つの例をそれぞれ一般化してきましょう。
ただし、その前に`method`メソッドには退場してもらい、`to_proc`を使う形で先ほどの例を書き直します。

```rb
# 1つ目
xs = %w`akechi kokoro itoh chika ayase ena koshimizu sachiko`
xs.map &:capitalize
```

1つ目はそのままです。

```rb
# 2つ目
xs = %w`明智小衣 伊藤千佳 綾瀬恵那 輿水幸子`
xs.map &:puts.to_proc.curry(2).call(Kernel)
```

2つ目、`curry`が出た。

```rb
# 3つ目
xs = (1..10)
xs.map &:**.to_proc.curry(2).call(2)
```

3つ目も`curry`だ。

というわけで一般化です。

|ブロックあり|ブロックなし|ブロックなし(to_proc)|
|---|---|---|
|xs.map{&#124;x&#124; x.foo }|xs.map(&:foo)|xs.map(&:foo.to_proc)|
|xs.map{&#124;x&#124; foo(x) }|xs.map(&method(:foo))|xs.map(&:foo.to_proc.curry(2).call(Kernel))|
|xs.map{&#124;x&#124; obj.foo(x) }|xs.map(&obj.method(:foo))|xs.map(&:foo.to_proc.curry(2).call(obj))|

このようにして、Procオブジェクトを`&`prefix付きで渡すとブロックの様に振る舞うという仕様を利用することにより、好みのProcオブジェクトを作り出すことさえできればブロックを伴わずに`map`操作が可能になるということがわかりました。（ちなみに`&:foo`の様にProcオブジェクトでなくシンボルを渡した場合は勝手に`to_proc`されます。）

`map`でなく普通のメソッド呼び出しとして一般化してみましょう。


|ブロックあり|ブロックなし(to_proc)|
|---|---|
|x.foo|:foo.to_proc.call(x)|
|foo(x)|:foo.to_proc.curry(2).call(Kernel).call(x)|
|obj.foo(x)|:foo.to_proc.curry(2).call(obj).call(x)|

Procオブジェクトを作ることで、任意のオブジェクトをレシーバとしてメソッド呼び出しを行うことができることがわかりました。

これをさらに一般化してみましょう。レシーバ`obj`のメソッド`foo`を、任意のn個のオブジェクトを実引数として渡して実行するコードが以下になります。ただし、`args`は任意のn個のオブジェクトを持つ`Array`インスタンスとします。

```rb
:foo.to_proc.curry(args.size + 1).call(obj).call(*args)
```

いいですね。Procオブジェクト最高。

## ブロックなしRuby上級

ここで問題です。今までのコードを踏まえた上で、次のコードをProcオブジェクトを実行(`call`メソッド呼び出し)する形に書き換えてください。ただし、ブロックを使ってはいけません。

```rb
xs = (1..10)
xs.map{|it|it.to_s(2)}
#=> ["1", "10", "11", "100", "101", "110", "111", "1000", "1001", "1010"]
```

…

……

………

どうですか？解けましたか？

実は、私の知る限り、ブロックを使わずに**Procオブジェクトの部分適用にて**この問題を解く方法はありません。

というのも、Rubyでは`Proc#curry`によってProcオブジェクトをカリー化することで、簡単に部分適用が行えるようになるものの、`Symbol#to_proc`によって生成されたProcオブジェクトが**第一引数としてメソッドを呼び出すレシーバのオブジェクトを取る**という仕様をしているため、レシーバを未定にし、メソッドの実引数のみ部分適用したProcオブジェクトを生成することが（ブロックなしでは）不可能なのです。

先ほどの問題を無理やり解こうとすると、

```rb
xs.map(&:to_s.to_proc.curry(2)).
  map(&:call.to_proc.curry(2)).
  map(&:call.to_proc.curry(2)).
  map(&:call.to_proc.curry(2)).
  map(&:call.to_proc.curry(2)).
  map(&:call.to_proc.curry(2)).
  ...
```

の様に無限に`map`のネストが続いてしまいます。

1行目の`xs.map(&:to_s.to_proc.curry(2))`によって、`map`の返り値として、第一引数、つまりメソッド呼び出し時のレシーバだけ部分適用したProcオブジェクトの`Enumerator`が得られます。あとはそのProcオブジェクトに対して第二引数である`2`を渡す形で`call`メソッドを実行してやればいいのですが、これは最初の目的であった**Enumeratorの各要素をレシーバとして、引数を1つ取るメソッドを呼び出す**という目的が、呼び出すメソッドが`to_s`から`call`に変わった状態であることがわかるかと思います。つまり、カリー化したProcオブジェクトの部分適用という形でこの問題を解くことは不可能です。

というわけでこの問題の答えは、「`each_with_object`を使う」です。以下にコードを示します。

```rb
xs.each_with_object(2).map &:to_s
```

`each_with_object`によって生成された`Enumerator`は、`yield`に2つの値を渡して実行します。これにより、`map`を使いProcオブジェクトに2つの引数を一度に渡して実行するということが可能になります。

`each_with_object`によって問題は解けたものの、`Symbol#to_proc`によって得られたProcオブジェクトをカリー化、部分適用し、レシーバだけが未定な状態であるProcオブジェクトを作り出すことは不可能であるということがわかりました。（もちろん、ブロック、つまりlambdaを使えば可能です）

この問題は、引数の順序を入れ替える`Proc#flip`などのメソッドがあれば解決します。この様に、あえてブロック禁止という縛りでプログラミングを行うことで、自然とProcやカリー化、部分適用などを用い、さらにEnumeratorへの操作適用をチェーンさせていくという、極めてLisp風とも言えるプログラミングの概念を自然に習得できますし、また同時に、**せっかく`Proc#curry`があるのに`Proc`に圧倒的にメソッド少なすぎるが故にProcオブジェクトをフル活用できない**ということを実感できるのではないかと思います。

## まとめ

- あえてブロックなしRubyをやることで`Proc`の限界が見えてくる
  - ブロック本当に便利ということが再認識できる
  - ブロックの利便性故にあんまり`Proc`に便利メソッド実装されないのかも
- [lambda_driver](https://github.com/yuroyoro/lambda_driver)かなりすごい（かなり）
- [Nendo](http://oldtype.sumibi.org/show-page/Nendo)かなりすごい（かなり）