2016-01-15 5 views
7

पर प्रो को चालू करते समय एक तर्क प्रदान करें हम आसानी से एक विधि को परिभाषित कर सकते हैं और इसे unary ampersand के साथ ब्लॉक में बदल सकते हैं।रूबी: एक ब्लॉक

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) 

क्या ब्लॉक में प्रो को चालू करते समय अतिरिक्त तर्क पारित करना संभव है?

+0

आप दोनों बहस उपज से बुलाया विधि से पारित किया जा करना चाहते हैं, या आप एक तर्क निर्दिष्ट करने के लिए करना चाहते हैं जब जमा करने: आप उदाहरण के लिए एक proc कि एक सरणी लेता है और एक तर्क सूची में बदल देता लौट सकते हैं विधि के लिए ब्लॉक? –

+2

बस ध्यान दें कि '[' foo ',' bar ']।प्रत्येक (और my_method) 'समझ में नहीं आता है क्योंकि प्रत्येक' हमेशा 'एक तत्व उत्पन्न करेगा। अपने प्रश्न का उत्तर नहीं दे रहा है, लेकिन '[' foo ', 3] .each_slice (2, और my_method) देखें। – ndn

+2

मुझे लगता है कि 'करी' इस प्रश्न की कुंजी हो सकती है। – sawa

उत्तर

1

your comment के बारे में:

अजीब है, लेकिन यह प्रदर्शन

दौरान तर्क स्वैप

दरअसल, तर्क आदेश संरक्षित है।

curry एक नई प्रोसेस देता है जो मूल विधि/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} 

आप एक curried 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} 

हालांकि, आप स्पष्ट रूप से तर्क आदेश को बदल नहीं सकते हैं।


currying के लिए एक वैकल्पिक आंशिक आवेदन जो एक या अधिक तर्क फिक्सिंग से कम arity के साथ एक नया 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"] 

बेशक

, आप नहीं कर रहे हैं एकल तर्क को ठीक करने तक ही सीमित है।

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 के साथ ऐसा कर सकते हैं।

प्रोक संस्करण:

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

आपकी अंतिम पंक्ति स्थानीय चर 'बहु' का संदर्भ देती है जिसे पहली पंक्ति में असाइन किया गया था, विधि नहीं। – Stefan

+0

@Stefan: अच्छी पकड़। – fylooi

+2

आप '[1, 2] .map (और विधि (: multi) .to_proc.curry [2]) का उपयोग कर सकते हैं, हालांकि, यह बोझिल दिखता है। – Stefan

संबंधित मुद्दे