# Ruby 1.8で任意のメソッドをカリー化するメソッドをつくる。
_published: 2010/09/10_ 
「辛いものが食べたい』と君が言ったから九月十日は、Ruby 1.8で任意のメソッドをカリー化するメソッドをつくる記念日。
- [カリー化 - Wikipedia](http://ja.wikipedia.org/wiki/%E3%82%AB%E3%83%AA%E3%83%BC%E5%8C%96)
Haskellで関数を書くと、勝手にカリー化しています。
```haskell
Prelude> let test a b c = a + b * c
Prelude> (((test 1) 2) 3)
7
```
Rubyでやるなら、こうなればいいわけです。
```ruby
def test(a, b, c)
a + b * c
end
curried_test = method(:test).curry
p curried_test.call(1).call(2).call(3) #=> 7
```
特定のメソッドをカリー化するなら、`lambda` をネストすればいいんですが。。任意のメソッドだと、ネストする階層を決定できません。文字列でコードをつくってevalすると簡単そうです。ですが、ここはあえて、`lambda` でなんとかしましょう。
再帰すればいいのですが、ここはあえてループで処理。内側から包んでいく感じで。引数の引渡しに悩みつつ。完成?
```ruby
class Method
def curry
args = []
f = self
self.arity.times do
f = wrap(f, args)
end
f.call
end
def wrap(f, args)
lambda {
lambda {|x|
args << x
f.call *args
}
}
end
end
```
正しく動くように見えましたが、呼び出しのたびに引数がどんどん増えていきます。そのため、エラーが発生。
```ruby
curried_test = method(:test).curry
p curried_test.call(1).call(2).call(3) #=> 7
p curried_test.call(1).call(2).call(3) #=> ArgumentError
```
`args` のスコープが広すぎるんですね。呼び出しのたびに状態が変化しています。
副作用をなくします。
```ruby
class Method
def curry
args = []
f = self
self.arity.times do
f = wrap(f)
end
f.call
end
def wrap(f)
lambda {|*args|
lambda {|x|
f.call *(args + [x])
}
}
end
end
```
できたー。
```ruby
curried_test = method(:test).curry
p curried_test.call(1).call(2).call(3) #=> 7
p curried_test.call(1).call(2).call(3) #=> 7
```
```ruby
curried_test = method(:test).curry
p f = curried_test.call(1) #=> <Proc:
[email protected]:17>
p f = f.call(2) #=> <Proc:
[email protected]:17>
p f.call(3) #=> 7
p f.call(4) #=> 9
```
今回は、Ruby 1.8とバージョンを限定しました。というのは、他の人の実装を見てみようと思い検索してみると、Ruby 1.9には `Proc` に `curry` メソッドが用意されていました。
```ruby
# Ruby 1.9
proc {|a, b, c| a + b * c}.curry[1][2][3] #=> 7
```
ちなみに、Ruby 1.9では、 `.call(1)` の代わりに `1` と書くことができます。
Rubyの引数の `*` を活用した解法です。同じような書き方ができない言語が多いかもしれません。他の解法を考えてみてください。