2016-01-15 5 views
7

メソッドを簡単に定義し、単項アンパサンドでブロックに変換できます。Ruby:procをブロックに変換する際に引数を指定します。

def my_method(arg) 
    puts arg*2 
end 

['foo', 'bar'].each(&method(:my_method)) 

# foofoo 
# barbar 

# or 
my_method = ->(arg) { puts arg*2 } 
['foo', 'bar'].each(&my_method) 
# same output 

私たちが集計で作業するとき、最初の引数が自動的に渡されることがわかります。しかし、2つ以上の引数を渡す必要がある場合はどうなりますか?

my_method = ->(arg,num) { puts arg*num } 
['foo', 'bar'].each(&my_method) 
# ArgumentError: wrong number of arguments (1 for 2) 
['foo', 'bar'].each(&my_method(3)) 
# NoMethodError: undefined method `foo' for main:Object 
['foo','bar'].each do |i, &my_method| 
    yield i, 3 
end 
# LocalJumpError: no block given (yield) 

procをブロックにする際に追加引数を渡すことは可能ですか?

+0

:あなたは、例えば、配列を取り、引数リストに変換PROCを返すことができますメソッドへのブロック? –

+2

'['foo'、 'bar']に注意してください。each(&my_method) 'は意味がありません。なぜなら、' each'は常にただ一つの要素を生成するからです。あなたの質問に答えるのではなく、 '['foo'、3] .each_slice(2、&my_method)'をチェックしてください。 – ndn

+2

「カレー」はこの質問の鍵かもしれないと思います。 – sawa

答えて

1

your commentについて:

奇妙な、しかし、それは演奏中の引数を交換

実際には、引数の次数に保存されています。

curryは、元のメソッド/ proc(そのアリティに基づいて)を呼び出すのに十分な引数があるまで、引数を効果的に収集する新しいprocを返します。これは、中間procsのを返すことによって達成される:

def foo(a, b, c) 
    { a: a, b: b, c: c } 
end 

curried_proc = foo.curry #=> #<Proc:0x007fd09b84e018 (lambda)> 
curried_proc[1]   #=> #<Proc:0x007fd09b83e320 (lambda)> 
curried_proc[1][2]  #=> #<Proc:0x007fd09b82cfd0 (lambda)> 
curried_proc[1][2][3]  #=> {:a=>1, :b=>2, :c=>3} 

あなたは一度カリーPROCへの任意の数の引数を渡すことができます。

curried_proc[1][2][3]  #=> {:a=>1, :b=>2, :c=>3} 
curried_proc[1, 2][3]  #=> {:a=>1, :b=>2, :c=>3} 
curried_proc[1][2, 3]  #=> {:a=>1, :b=>2, :c=>3} 
curried_proc[1, 2, 3]  #=> {:a=>1, :b=>2, :c=>3} 

空の引数は無視されます。

しかし
curried_proc[1][][2][][3] #=> {:a=>1, :b=>2, :c=>3} 

、明らかに引数の順序を変更することはできません。


カリー化する代わりに、1つ以上の引数を固定することにより、下部アリティと新しいPROCを返し部分アプリケーションあります。 curryとは違って、そこに部分的なアプリケーションのための組み込みメソッドませんが、あなたは簡単に書くことができ、あなた自身:

my_proc = -> (arg, num) { arg * num } 

def fix_first(proc, arg) 
    -> (*args) { proc[arg, *args] } 
end 

fixed_proc = fix_first(my_proc, 'foo') #=> #<Proc:0x007fa31c2070d0 (lambda)> 
fixed_proc[2] #=> "foofoo" 
fixed_proc[3] #=> "foofoofoo" 

[2, 3].map(&fixed_proc) #=> ["foofoo", "foofoofoo"] 

か、最後の引数固定:もちろん

def fix_last(proc, arg) 
    -> (*args) { proc[*args, arg] } 
end 

fixed_proc = fix_last(my_proc, 2) #=> #<Proc:0x007fa31c2070d0 (lambda)> 
fixed_proc['foo'] #=> "foofoo" 
fixed_proc['bar'] #=> "barbar" 

['foo', 'bar'].map(&fixed_proc) #=> ["foofoo", "barbar"] 

を、あなたはそうではありません単一の引数を修正することに限定されます。あなたは両方の引数が降伏によって呼び出されたメソッドから渡されたことにしますか、または提出する際に使用すると、1つの引数を指定したいん

def splat_args(proc) 
    -> (array) { proc[*array] } 
end 

splatting_proc = splat_args(my_proc) 
[['foo', 1], ['bar', 2], ['baz', 3]].map(&splatting_proc) 
#=> ["foo", "barbar", "bazbazbaz"] 
6

@sawaが正しいです。 curryでそれを行うことができます。

PROCバージョン:

mult = proc {|a, b| a * b} # => #<Proc:[email protected](irb):32> 
[1, 2].map(&mult.curry[2]) # => [2, 4] 

メソッドのバージョン:

def mult(a, b) 
    a*b 
end 

[1, 2].map(&method(:mult).to_proc.curry[2]) # => [2, 4] 
+2

最後の行は、メソッドではなく、最初の行に割り当てられたローカル変数 'mult 'を参照します。 – Stefan

+0

@Stefan:いいキャッチ。 – fylooi

+2

'[1、2] .map(&mult(。mult).to_proc.curry [2])'を使うことはできますが、扱いにくいです。 – Stefan

関連する問題