रूबी में एक खरीद और एक मेमने के बीच क्या अंतर है?


176

और आप एक के बजाय एक का उपयोग कब करेंगे?


Jtbandes के जवाब के अलावा, इस बात में भी अंतर है कि returnस्टेटमेंट procबनाम में से क्या लौटाता है lambda
केन ब्लूम


2
यहाँ अधिक विस्तृत उत्तर है: stackoverflow.com/questions/626/…
Dan KK

जवाबों:


260

एक तरह से वे तर्क को संभालने के तरीके में है। का उपयोग कर एक खरीद बनाने proc {}और Proc.new {}समकक्ष हैं। हालाँकि, इसका उपयोग करने lambda {}से आपको एक सलाह मिलती है जो इसके लिए दिए गए तर्कों की संख्या की जांच करता है। से ri Kernel#lambda:

Proc.new के समतुल्य , जिसके परिणामस्वरूप Proc ऑब्जेक्ट्स को बुलाए जाने पर पारित किए गए मापदंडों की संख्या की जांच करते हैं।

एक उदाहरण:

p = Proc.new {|a, b| puts a**2+b**2 } # => #<Proc:0x3c7d28@(irb):1>
p.call 1, 2 # => 5
p.call 1 # => NoMethodError: undefined method `**' for nil:NilClass
p.call 1, 2, 3 # => 5
l = lambda {|a, b| puts a**2+b**2 } # => #<Proc:0x15016c@(irb):5 (lambda)>
l.call 1, 2 # => 5
l.call 1 # => ArgumentError: wrong number of arguments (1 for 2)
l.call 1, 2, 3 # => ArgumentError: wrong number of arguments (3 for 2)

इसके अलावा, जैसा कि केन बताते हैं, returnएक लैम्ब्डा के अंदर का उपयोग उस लैम्ब्डा के मूल्य को लौटाता है, लेकिन returnएनक्लोजिंग ब्लॉक से एक खरीद रिटर्न में उपयोग करता है।

lambda { return :foo }.call # => :foo
return # => LocalJumpError: unexpected return
Proc.new { return :foo }.call # => LocalJumpError: unexpected return

इसलिए अधिकांश त्वरित उपयोगों के लिए वे समान हैं, लेकिन यदि आप स्वचालित सख्त तर्क जाँच चाहते हैं (जो कभी-कभी डिबगिंग में भी मदद कर सकते हैं), या यदि आपको खरीद returnके मूल्य को वापस करने के लिए कथन का उपयोग करने की आवश्यकता है , तो उपयोग करें lambda


8
क्या यह कहना सही होगा कि लंबोदर तरीके बहुत पसंद हैं (जांच की दलीलें और उनके पास से लौटें), जबकि प्रोक्स बहुत ज्यादा ब्लॉक की तरह हैं (तर्क की जांच नहीं की जाती है और एक वापसी युक्त विधि या लैम्ब्डा से वापस आ जाएगी)?
प्रातः

मैं भगवान को जानता हूं कि अब तक कितने वेबसाइट और लेख हैं और किसी को भी प्रोक्स बनाम तरीकों बनाम लैम्ब्डा की उपयोगिता के बारे में बात करना प्रतीत नहीं होता है। हर स्पष्टीकरण सिर्फ एक बाल-विभाजन विवरण प्रदान करता है कि कैसे रिटर्न वैल्यू, आदि, अलग-अलग हैं, लेकिन कोई भी क्यों यह मायने रखता है। अभी के लिए मुझे यह निष्कर्ष निकालना होगा कि यह रूबी में एक डिजाइन गड़बड़ है।
ankush981

76

प्रोक्स और लैम्ब्डा के बीच वास्तविक अंतर सब कुछ नियंत्रण प्रवाह कीवर्ड के साथ करना है। मैं बात कर रहा हूँ return, raise, break, redo, retryउन नियंत्रण शब्द - आदि। मान लीजिए कि किसी प्रॉप में आपका रिटर्न स्टेटमेंट है। जब आप अपने खरीद को बुलाते हैं, तो यह न केवल आपको इससे बाहर निकाल देगा, बल्कि संलग्नक विधि से भी लौटेगा:

def my_method
  puts "before proc"
  my_proc = Proc.new do
    puts "inside proc"
    return
  end
  my_proc.call
  puts "after proc"
end

my_method

shoaib@shoaib-ubuntu-vm:~/tmp$ ruby a.rb
before proc
inside proc

putsविधि में अंतिम , कभी भी निष्पादित नहीं किया गया था, जब से हमने अपनी खरीद को बुलाया, तो returnभीतर ने हमें विधि से बाहर निकाल दिया। अगर, हालांकि, हम अपने खरीद को एक लंबोदर में बदल देते हैं, तो हमें निम्नलिखित मिलते हैं:

def my_method
  puts "before proc"
  my_proc = lambda do
    puts "inside proc"
    return
  end
  my_proc.call
  puts "after proc"
end

my_method
shoaib@shoaib-ubuntu-vm:~/tmp$ ruby a.rb
before proc
inside proc
after proc

लैम्ब्डा के भीतर वापसी ही हमें लैम्ब्डा से बाहर निकाल देती है और एन्कोडिंग विधि निष्पादित करती रहती है। जिस तरह से नियंत्रण प्रवाह कीवर्ड का इलाज प्रॉक्स और लैम्ब्डा के भीतर किया जाता है, उनके बीच मुख्य अंतर है


7

केवल दो मुख्य अंतर हैं।

  • सबसे पहले, एक lambdaतर्कों की संख्या उसके पास गई, जबकि procऐसा नहीं है। इसका मतलब यह है कि lambdaयदि आप इसे गलत तर्क देते हैं, तो आप एक त्रुटि को फेंक देंगे, जबकि एक procअप्रत्याशित तर्क को नजरअंदाज कर देगा और nilजो गायब है उसे असाइन करेगा ।
  • दूसरा, जब कोई lambdaरिटर्न देता है, तो यह कॉलिंग विधि पर वापस नियंत्रण से गुजरता है; जब कोई procरिटर्न देता है, तो वह तुरंत ऐसा करता है, बिना कॉलिंग विधि के।

यह कैसे काम करता है यह देखने के लिए, नीचे दिए गए कोड पर एक नज़र डालें। हमारी पहली विधि एक कॉल proc; दूसरा फोन करता है lambda

def batman_ironman_proc
  victor = Proc.new { return "Batman will win!" }
  victor.call
  "Iron Man will win!"
end

puts batman_ironman_proc # prints "Batman will win!"

def batman_ironman_lambda
  victor = lambda { return "Batman will win!" }
  victor.call
  "Iron Man will win!"
end

puts batman_ironman_lambda # prints "Iron Man will win!"

देखें कि procबैटमैन कैसे जीतेंगे, "बैटमैन जीतेगा!", यह इसलिए है क्योंकि यह तुरंत वापस लौटता है।

हमारा lambda, हालांकि, बुलाए जाने के बाद विधि में वापस चला जाता है, इसलिए विधि अंतिम कोड को वापस कर देती है जो इसका मूल्यांकन करता है: "आयरन मैन जीत जाएगा!"


5

# प्रोक उदाहरण

p = Proc.new { |x| puts x*2 }
[1,2,3].each(&p)              # The '&' tells ruby to turn the proc into a block 

proc = Proc.new { puts "Hello World" }
proc.call

# लैंबडा उदाहरण

lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           

प्रोक्स और लैम्ब्डा के बीच अंतर

इससे पहले कि मैं procs और lambdas के बीच अंतर करता हूं, यह उल्लेख करना महत्वपूर्ण है कि वे दोनों प्रोक ऑब्जेक्ट हैं।

proc = Proc.new { puts "Hello world" }
lam = lambda { puts "Hello World" }

proc.class # returns 'Proc'
lam.class  # returns 'Proc'

हालाँकि, लैम्ब्डा प्रोक्स का एक अलग 'स्वाद' है। वस्तुओं को वापस करते समय यह मामूली अंतर दिखाया गया है।

proc   # returns '#<Proc:0x007f96b1032d30@(irb):75>'
lam    # returns '<Proc:0x007f96b1b41938@(irb):76 (lambda)>'

1. लैम्ब्डा तर्कों की संख्या की जांच करते हैं, जबकि प्रोक्स नहीं करते हैं

lam = lambda { |x| puts x }    # creates a lambda that takes 1 argument
lam.call(2)                    # prints out 2
lam.call                       # ArgumentError: wrong number of arguments (0 for 1)
lam.call(1,2,3)                # ArgumentError: wrong number of arguments (3 for 1)

इसके विपरीत, अगर वे तर्क की गलत संख्या से गुज़र जाते हैं, तो प्रॉक्स परवाह नहीं करते हैं।

proc = Proc.new { |x| puts x } # creates a proc that takes 1 argument
proc.call(2)                   # prints out 2
proc.call                      # returns nil
proc.call(1,2,3)               # prints out 1 and forgets about the extra arguments

2. लैम्ब्डा और प्रोक्स 'रिटर्न' कीवर्ड को अलग तरह से मानते हैं

एक लैम्ब्डा के अंदर 'रिटर्न' कोड को लैम्ब्डा कोड के ठीक बाहर चलाता है

def lambda_test
  lam = lambda { return }
  lam.call
  puts "Hello world"
end

lambda_test                 # calling lambda_test prints 'Hello World'

किसी प्रॉप के अंदर 'रिटर्न' उस विधि के बाहर कोड को ट्रिगर करता है जहां प्रॉप को निष्पादित किया जा रहा है

def proc_test
  proc = Proc.new { return }
  proc.call
  puts "Hello world"
end

proc_test                 # calling proc_test prints nothing

और आपके अन्य प्रश्न का उत्तर देने के लिए, कौन सा उपयोग करना है और कब? मैं @jtbandes का पालन करूँगा जैसा कि उसने उल्लेख किया है

इसलिए अधिकांश त्वरित उपयोगों के लिए वे समान हैं, लेकिन यदि आप स्वचालित सख्त तर्क जाँच चाहते हैं (जो कभी-कभी डिबगिंग में भी मदद कर सकते हैं), या यदि आपको खरीद के मूल्य को वापस करने के लिए रिटर्न स्टेटमेंट का उपयोग करने की आवश्यकता है, तो लैम्ब्डा का उपयोग करें।

मूल रूप से यहां तैनात हैं


1

आमतौर पर, मेमनों की तुलना में लंबोदर अधिक सहज होते हैं क्योंकि वे विधियों के समान होते हैं। वे आरती के बारे में बहुत सख्त हैं, और जब आप वापसी कहते हैं तो वे बस बाहर निकल जाते हैं। इस कारण से, कई रूबीवादी पहली पसंद के रूप में लैम्ब्डा का उपयोग करते हैं, जब तक कि उन्हें प्रोक्स की विशिष्ट विशेषताओं की आवश्यकता नहीं होती है।

गुण: वर्ग की वस्तुएँ Proc। ब्लॉक की तरह, उनका मूल्यांकन उस दायरे में किया जाता है जहां वे परिभाषित होते हैं। लैम्ब्डा: क्लास की वस्तुएं भी Procलेकिन नियमित रूप से प्रॉक्स से अलग। वे ब्लॉक और प्रोक्स की तरह बंद कर रहे हैं, और जैसे कि वे उस दायरे में मूल्यांकन किए जाते हैं जहां वे परिभाषित हैं।

प्रोक का निर्माण

a = Proc.new { |x| x 2 }

मेमना बनाना

b = lambda { |x| x 2 }


a = proc { |x| x 2 }के रूप में ही हैa = Proc.new { |x| x 2 }
लैकोस्टेनिकोडर

1

यहाँ इसे समझने का एक और तरीका है।

एक ब्लॉक एक वस्तु पर विधि के एक कॉल के लिए मंगलाचरण से जुड़ा कोड का एक हिस्सा है। नीचे दिए गए उदाहरण में, Self एक अनाम वर्ग का एक उदाहरण है, जो ActionView :: बेस इन द रेल्स फ्रेमवर्क (जिसमें स्वयं कई सहायक मॉड्यूल शामिल हैं) से विरासत में मिला है। कार्ड एक ऐसी विधि है जिसे हम स्वयं कहते हैं। हम विधि के तर्क में पास हो जाते हैं और फिर हम हमेशा ब्लॉक को विधि के अंत में संलग्न करते हैं:

self.card :contacts do |c|
  // a chunk of valid ruby code    
end

ठीक है, इसलिए हम एक विधि के लिए कोड का एक हिस्सा पारित कर रहे हैं। लेकिन हम इस ब्लॉक का उपयोग कैसे करते हैं? एक विकल्प यह है कि कोड का हिस्सा किसी वस्तु में बदल दिया जाए। रूबी एक कोड के एक वस्तु में बदलने के लिए तीन तरीके प्रदान करता है

# lambda
> l = lambda { |a| a + 1 }
> l.call(1)
=> 2 

# Proc.new
> l2= Proc.new { |a| a + 1 }
> l2.call(1)
=> 2 

# & as the last method argument with a local variable name
def add(&block)
end

ऊपर दी गई विधि में, & ब्लॉक को एक ऑब्जेक्ट में विधि में कनवर्ट करता है और उस ऑब्जेक्ट को स्थानीय वैरिएबल ब्लॉक में स्टोर करता है। वास्तव में, हम यह दिखा सकते हैं कि इसमें लैम्ब्डा और Proc.new जैसा ही व्यवहार है:

def add(&block)
  block
end

l3 = add { |a| a + 1 }
l3.call(1)
=> 2

यह महत्वपूर्ण है। जब आप किसी ब्लॉक को एक विधि से गुजारते हैं और इसका उपयोग करके उसे परिवर्तित करते हैं, तो वह जो वस्तु बनाता है वह रूपांतरण करने के लिए Proc.new का उपयोग करता है।

ध्यान दें कि मैंने एक विकल्प के रूप में "proc" के उपयोग से बचा था। ऐसा इसलिए है क्योंकि यह रूबी 1.8 है, यह लैम्ब्डा के समान है और रूबी 1.9 में, यह प्रोटॉन की तरह ही है और सभी रूबी संस्करणों में इसे टाला जाना चाहिए।

तो फिर आप पूछते हैं कि लैम्ब्डा और प्रोटॉन में क्या अंतर है?

सबसे पहले, पैरामीटर पासिंग के संदर्भ में, लैम्बडा एक विधि कॉल की तरह व्यवहार करता है। यदि आप तर्क की गलत संख्या पास करते हैं तो यह एक अपवाद को बढ़ाएगा। इसके विपरीत, Proc.new समानांतर असाइनमेंट की तरह व्यवहार करता है। सभी अप्रयुक्त तर्क शून्य में परिवर्तित हो जाते हैं:

> l = lambda {|a,b| puts "#{a} + #{b}" }
 => #<Proc:0x007fbffcb47e40@(irb):19 (lambda)> 
> l.call(1)
ArgumentError: wrong number of arguments (1 for 2)

> l2 = Proc.new {|a,b| puts "#{a} + #{b}" }
=> #<Proc:0x007fbffcb261a0@(irb):21> 
> l2.call(1)
1 + 

दूसरा, लैम्ब्डा और प्रॉन्यूव रिटर्न कीवर्ड को अलग-अलग तरीके से हैंडल करते हैं। जब आप Proc.new के अंदर एक वापसी करते हैं, तो यह वास्तव में संलग्न विधि, यानी आसपास के संदर्भ से लौटता है। जब आप लंबोदर ब्लॉक से लौटते हैं, तो यह ब्लॉक से वापस लौटता है, न कि संलग्न पद्धति से। मूल रूप से, यह कॉल से ब्लॉक तक बाहर निकलता है और बाकी संलग्न विधि के साथ निष्पादन जारी रखता है।

> def add(a,b)
  l = Proc.new { return a + b}
  l.call
  puts "now exiting method"
end
> add(1,1)
=> 2  # NOTICE it never prints the message "now exiting method"

> def add(a,b)
  l = lambda { return a + b }
  l.call
  puts "now exiting method"
end
> add(1,1)
=> now exiting method  # NOTICE this time it prints the message "now exiting method"

तो यह व्यवहार भिन्नता क्यों? इसका कारण यह है कि Proc.new के साथ, हम पुनरावृत्तियों का उपयोग संलग्न तरीकों के संदर्भ में कर सकते हैं और तार्किक निष्कर्ष निकाल सकते हैं। इस उदाहरण को देखें:

> def print(max)
  [1,2,3,4,5].each do |val|
    puts val
    return if val > max
  end
end
> print(3)
1
2
3
4

हम उम्मीद करते हैं कि जब हम पुनरावृत्त के अंदर वापसी का आह्वान करेंगे, तो यह संलग्न पद्धति से वापस आ जाएगा। याद रखें कि पुनरावृत्तियों को पारित ब्लॉक Proc.new का उपयोग करते हुए वस्तुओं में परिवर्तित हो जाते हैं और यही कारण है कि जब हम वापसी का उपयोग करते हैं, तो यह संलग्न विधि से बाहर निकल जाएगा।

आप लंबोदर को गुमनाम तरीकों के रूप में सोच सकते हैं, वे कोड के अलग-अलग ब्लॉकों को एक ऑब्जेक्ट में अलग करते हैं जिसे एक विधि की तरह माना जा सकता है। अंत में, एक लैम्ब्डा के बारे में सोचें जैसा कि एक विचारात्मक पद्धति के रूप में व्यवहार कर रहा है और इनलाइन कोड के रूप में व्यवहार कर रहा है।


0

रूबी गाइड पर एक सहायक पोस्ट: ब्लॉक, प्रॉक्स और लैम्ब्डा

वर्तमान विधि से प्रोक्स वापस आते हैं, जबकि लैम्ब्डा लैम्बडा से ही वापस आते हैं।

Procs तर्क की सही संख्या के बारे में परवाह नहीं करते हैं, जबकि लैम्ब्डा एक अपवाद उठाएंगे।


-3

proc और lambda के बीच अंतर यह है कि proc कोड की एक प्रति है जिसके बदले में तर्कों को प्रतिस्थापित किया जाता है, जबकि lambda अन्य भाषाओं की तरह एक फ़ंक्शन है। (वापसी का व्यवहार, तर्कों की जाँच)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.