2

カリー化をサポートするRuby1.9は、任意の数の引数を取るprocを処理する2つの方法をサポートしています。

my_proc = proc {|*x| x.max }

1)curry引数なし:my_proc.curry。通常のprocと同じように、カンマ区切りの引数をcurriedprocに渡します。引数の数が任意である場合、これは適切なカリー化を達成しません(引数の一部がスプラットでない場合に役立ちます)

2)curry引数付き:my_proc.curry(n)このように、カリー化は、procが引数を取るかのように適用されnます。例えば:

my_proc.curry(3).call(2).call(5).call(1) #=> 5

では、どのようにして任意の数の引数でカリー化を実現しますか?つまり、n与えられていない場合は?

私の頭に浮かぶ1つの方法は、プロキシを介して引数を収集し、次にviacallを解決することです(引数なしで使用されている/使用されている以外のメソッドがある場合は、収集された引数を使用してを呼び出します)が、他の方法を探していますそれを達成するために。procmethod_missingcallcallproc

アップデート

Andy Hが述べたように、問題はいつカリー化をやめるかです。私の目的では、カリー化が停止したり、他のメソッドcallが呼び出されたとき、またはcall引数なしで呼び出されたときにprocが評価したりしても問題ありません。

4

3 に答える 3

7

組み込みのcurry方法は機能しません。その理由は、そうするのに十分な引数があるとすぐに評価する proc を生成するためです。リンク先のドキュメントを引用します。

カリー化された proc はいくつかの引数を受け取ります。十分な数の引数が指定されている場合、指定された引数を元のプロシージャに渡し、結果を返します。

ここで理解すべき重要なポイントは、ゼロが splat パラメーターの「十分な数の引数」であるということです。

f = ->(x, y, z, *args){ [x, y, z, args] } 
g = f.curry    # => a "curryable" proc
h = g.call(1)  # => another curryable proc
i = h.call(2)  # => another curryable proc
j = i.call(3)  # => [1, 2, 3, []]

あなたが示すように、これらの「カリー化可能な」プロシージャは、一度に1つずつ引数を渡すことができ、十分な引数が渡されるまで新しいカリー化可能なプロシージャを返すたびに評価されます。これは、任意の長さの引数リストをサポートできなかった理由でもあります.カリー化を停止して評価する時期をどのように知るのでしょうか?

任意の数の引数を許可する別のカリー化方法が必要な場合は、独自のカリー メソッドを定義できます。

def my_curry(f, *curried_args)
  ->(*args) { f.call(*curried_args, *args) }
end

これはかなり単純化された実装ですが、目的には役立つかもしれません。組み込みメソッドとの主な違いは、十分な引数が渡された場合でも常に新しい proc を返すことと、一度に 1 つずつ「カリー チェーン」をサポートしないことです。

f = ->(x, y, z, *args) { [x, y, z, args] }

g = my_curry(f, 1)    # => a proc
g.call(2, 3)          # => [1, 2, 3, []] 
g.call(2, 3, 4, 5)    # => [1, 2, 3, [4, 5]]
g.call(2)             # => ArgumentError: wrong number of arguments (2 for 3)

h = my_curry(g, 2, 3) # => a proc
h.call                # => [1, 2, 3, []]
h.call(4, 5)          # => [1, 2, 3, [4, 5]]
于 2013-02-08T09:23:49.270 に答える
2

I hate to be humpfhoxious, but how about forget curry and just write

my_proc = proc { |*x| x.max }
l = -> *x { my_proc.( 4, 6, 12, 1, *x ) }
l.call + 1 #=> 13

You know, Matz himself said that curry is "just a toy for functional kids". Its implementation is not special, it is not faster or different from what you see above. Curry is not that useful in Ruby...

And for those who do not believe what I say, here is the exact quote and link:

Easter Egg for Functional Programming Kids

于 2013-02-08T16:28:49.553 に答える
0

のサブクラスをBasic Objectラッパーとして使用してカリー化を行うソリューションを実現しました。

class CurryWrap < BasicObject

  def initialize proc
    @proc = proc
    @args = []
    return self
  end

  def call *args
    if args.size == 1
      @args << args.first
      return self
    elsif args.empty?
      return @proc.call(*@args)
    else
      @proc.call(*@args).call(*args)
    end
  end

  def == other
    @proc.call(*@args) == other
  end

  def method_missing m, *args, &block
    @proc.call(*@args).send(m, *args, &block)
  end

end

これにより、基本的に次のことができます。

my_proc = proc { |*x| x.max }

CurryWrap.new(my_proc).call(4).call(6).call(12).call(1) + 1 #=> 13

引数以外callのものは、proc を解決します。

ただし、これがこれを行う最もエレガントな方法であるかどうかはわかりません。そのため、現時点では回答を受け入れないままにします。

于 2013-02-08T11:08:09.887 に答える