LoginSignup
5
4

More than 5 years have passed since last update.

Rubyでクロージャを使いたい(カリー化・部分適用)

Posted at

Procクラスとかラムダ式とかクロージャとかって知識としては知ってるけど、実際に使うことってあんまりない。というか使う腕がない、でも使いこなしたい。前回は初歩的なクロージャの練習として、いくつかのサンプルを作成してみた。

Rubyでクロージャを使いたい(導入編)

今回は部分適用やカリー化について勉強してみました。

部分適用、カリー化の定義

言葉の定義については以下のリンクが詳しいです。
カリー化:Wikipedia
Proc#curryについて

つまり、複数の引数をとる(一般的な形式の)関数を、部分適用可能な形の関数に変換することをカリー化と呼ぶのかな?

例えば二つの引数の和を返す関数func_sumがあるとする。

def func_sum(x, y)
    x + y
end

p func_sum(3,6) #=>9

これを部分適用可能な形にすると、次のようになる

#この書き方は無効です。
def func_sum(x)
    def func_sum_y(y)
        x + y
    end
end

p func_sum(3)(9)

と言いたいところだけど、Rubyではこのような構文は存在しないので実際はProcオブジェクトを用いて以下のように書く。

func_sum = ->(x){
    ->(y){
        x + y
    }
}

p func_sum.call(3).call(9) #=>12

サンプル

部分適用

例えば与えられた整数nの倍数が順番にm個格納されている配列を返す関数を作るとする。そしてこの整数nの部分を部分適用したい。具体的には以下のような感じ


multiple_of_3 = multiple_of.call(3)
p multiple_of_3.call(3) #=>[3,6,9]
p multiple_of_3.call(6) #=>[3,6,9,12,15,18]

multiple_ofオブジェクトを基としたmultiple_of_3インスタンスを宣言し、倍数の数が3個と6個でcallしている。

このmultiple_ofオブジェクトは例えば以下のように定義できる。

multiple_of = ->(n){
    ->(m){
        ary = []
        m.times do |i|
            ary << (i+1) * n
        end
        return ary
    }
}

しかしこの書き方はラムダ式がネストされており、見づらい上に分かりづらい。

カリー化

上で行った処理をカリー化を用いて再現すると以下のようになる

multiple_of = ->(n, m){
    ary = []
    m.times do |i|
        ary << (i+1) * n
    end
    return ary
}

multiple_of_3 = multiple_of.curry.call(3)
p multiple_of_3.call(3) #=>[3,6,9]
p multiple_of_3.call(6) #=>[3,6,9,12,15,18]

Proc#curryメソッドを用いてmultiple_ofをカリー化し、第一引数を渡した上でmultiple_of_3インスタンスに渡している。これなら引数を二つ受け取る通常のメソッドに近い形なので読みやすい。今回は引数が二つだけなのでありがたみが感じられないが、もっと複雑な処理を部分適用させたい場合は便利かも。

十分に理解できてないので、うまく説明できていないと思う。実際に有効活用できる場面がイマイチ想像できない。

5
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4