रूबी 1.8 में, एक तरफ proc / lambda और दूसरी तरफ के बीच सूक्ष्म अंतर हैं Proc.new
।
- वे अंतर क्या हैं?
- क्या आप इस बारे में दिशानिर्देश दे सकते हैं कि किसको चुनना है?
- रूबी 1.9 में, proc और लैम्ब्डा अलग हैं। क्या बात है?
रूबी 1.8 में, एक तरफ proc / lambda और दूसरी तरफ के बीच सूक्ष्म अंतर हैं Proc.new
।
जवाबों:
एक और महत्वपूर्ण लेकिन सूक्ष्म अंतर के साथ निर्मित lambda
और procs के साथ बनाया गया Proc.new
है कि वे return
कथन को कैसे संभालते हैं :
lambda
गंभीर खरीद में, return
बयान केवल खरीद से वापस आ जाता हैProc.new
गंभीर खरीद में, return
बयान थोड़ा और अधिक आश्चर्यजनक है: यह न केवल खरीद से नियंत्रण लौटाता है, बल्कि खरीद को घेरने की विधि से भी!यहां बताया गया है lambda
-created proc के return
कार्रवाई में। यह इस तरह से व्यवहार करता है जैसा कि आप शायद उम्मीद करते हैं:
def whowouldwin
mylambda = lambda {return "Freddy"}
mylambda.call
# mylambda gets called and returns "Freddy", and execution
# continues on the next line
return "Jason"
end
whowouldwin
#=> "Jason"
अब यहाँ एक है Proc.new
-created proc के return
ही बात कर। आप उन मामलों में से एक को देखने वाले हैं, जहां रूबी कम से कम कम से कम आश्चर्य के सिद्धांत को तोड़ती है:
def whowouldwin2
myproc = Proc.new {return "Freddy"}
myproc.call
# myproc gets called and returns "Freddy",
# but also returns control from whowhouldwin2!
# The line below *never* gets executed.
return "Jason"
end
whowouldwin2
#=> "Freddy"
यह आश्चर्य की बात व्यवहार (और साथ ही कम लिख कर) के लिए धन्यवाद, मैं का उपयोग कर के पक्ष में जाते हैं lambda
से अधिक Proc.new
जब procs बना रही है।
proc
विधि भी है । क्या यह सिर्फ एक आशुलिपि है Proc.new
?
proc
के बराबर हैProc.new
proc
कार्य करता है की तरह lambda
और नहीं की तरह Proc.new
वापसी बयान के संबंध में। इसका मतलब है कि माणिक डॉक गलत है।
proc
तरह काम करता है lambda
, लेकिन Proc.new
1.9 की तरह काम करता है । पीटर वेजनेट का जवाब देखें।
lambda
अनाम विधि है। चूंकि यह एक विधि है, यह एक मान लौटाता है, और जिस विधि ने इसे बुलाया है वह इसके साथ जो चाहे कर सकता है, इसे अनदेखा करने और एक अलग मान वापस करने सहित। A Proc
कोड स्निपेट में चिपकाने जैसा है। यह एक विधि की तरह काम नहीं करता है। इसलिए जब वापसी होती है Proc
, तो यह उस पद्धति के कोड का एक हिस्सा है जो इसे कहते हैं।
आगे स्पष्टीकरण प्रदान करने के लिए:
जॉय का कहना है कि वापसी का व्यवहार Proc.new
आश्चर्यजनक है। हालाँकि जब आप मानते हैं कि Proc.new एक ब्लॉक की तरह व्यवहार करता है तो यह आश्चर्य की बात नहीं है क्योंकि ठीक यही है कि ब्लॉक कैसे व्यवहार करते हैं। दूसरी ओर लांबा तरीकों की तरह अधिक व्यवहार करते हैं।
यह वास्तव में समझाता है कि प्रोक्स लचीले क्यों होते हैं जब यह arity (तर्कों की संख्या) की बात आती है जबकि लैम्ब्डा नहीं हैं। ब्लॉक को अपने सभी तर्कों को प्रदान करने की आवश्यकता नहीं है, लेकिन विधियां (जब तक कोई डिफ़ॉल्ट प्रदान नहीं की जाती है)। जबकि लैम्ब्डा डिफॉल्ट डिफ़ॉल्ट प्रदान करना रूबी 1.8 में एक विकल्प नहीं है, अब यह रूबी 1.9 में वैकल्पिक लैम्ब्डा सिंटैक्स (वेबमैट द्वारा नोट किया गया) के साथ समर्थित है:
concat = ->(a, b=2){ "#{a}#{b}" }
concat.call(4,5) # => "45"
concat.call(1) # => "12"
और Michiel de Mare (ओपी) के बारे में गलत है Procs और लैम्ब्डा रूबी 1.9 में arity के साथ एक ही व्यवहार। मैंने सत्यापित किया है कि वे अभी भी ऊपर बताए अनुसार 1.8 से व्यवहार बनाए रखते हैं।
break
कथन वास्तव में या तो प्रॉक्स या लैम्ब्डा में बहुत ज्यादा मायने नहीं रखते हैं। Procs में, ब्रेक आपको Proc.new से लौटा देगा जो पहले ही पूरा हो चुका है। और इसका कोई मतलब नहीं है कि एक लंबोदर से तोड़ने के लिए क्योंकि यह अनिवार्य रूप से एक विधि है, और आप एक विधि के शीर्ष स्तर से कभी नहीं टूटेंगे।
next
, redo
और raise
प्रोक्स और लैम्ब्डा दोनों में समान व्यवहार करते हैं। जबकि retry
दोनों में अनुमति नहीं है और कोई अपवाद नहीं उठाएगा।
और अंत में, proc
विधि का उपयोग कभी नहीं किया जाना चाहिए क्योंकि यह असंगत है और अप्रत्याशित व्यवहार है। रूबी 1.8 में यह वास्तव में एक लैम्ब्डा लौटाता है! रूबी 1.9 में यह तय किया गया है और यह एक प्रोक लौटाता है। यदि आप एक प्रोक बनाना चाहते हैं, तो साथ रहें Proc.new
।
अधिक जानकारी के लिए, मैं ओ'रेली की द रूबी प्रोग्रामिंग लैंग्वेज की अत्यधिक अनुशंसा करता हूं जो इस जानकारी के अधिकांश के लिए मेरा स्रोत है।
break
प्रोक्स से उठता है LocalJumpError
, जबकि break
लैम्ब्डा से बस return
( जैसे , return nil
) व्यवहार करता है ।
मैंने पाया यह पेज जो शो क्या बीच का अंतर Proc.new
और lambda
कर रहे हैं। पृष्ठ के अनुसार, एकमात्र अंतर यह है कि एक लंबोदर उस तर्क की संख्या के बारे में सख्त है जिसे वह स्वीकार करता है, जबकि Proc.new
लापता तर्क को परिवर्तित करता है nil
। यहाँ एक उदाहरण IRB सत्र है जो अंतर दिखाता है:
irb (मुख्य): 001: 0> l = lambda {| x, y x + y} => # <प्रोक: 0x00007fc605ec0748 @ (irb): 1> irb (मुख्य): 002: 0> p = Proc.new {| x, y | x + y} => # <प्रोक: 0x00007fc605ea8698 @ (irb): 2> irb (मुख्य): 003: 0> l.call "हैलो", "दुनिया" => "हेलोवर्ल्ड" irb (मुख्य): 004: 0> p.call "हैलो", "वर्ल्ड" => "हेलोवर्ल्ड" irb (मुख्य): 005: 0> l.call "हैलो" तर्क-वितर्क: तर्क की गलत संख्या (2 के लिए 1) (irb) से: 1 (irb) से: 5: `कॉल 'में (irb) से: 5 से: 0 irb (मुख्य): 006: 0> p.call "हैलो" TypeError: nil को String में नहीं बदल सकते (irb) से: 2: `+ 'में (irb) से: 2 (irb) से: 6: `कॉल 'में (irb) से: 6 से: 0
जब तक आप विशेष रूप से त्रुटि सहिष्णु व्यवहार नहीं चाहते हैं, तब तक पेज लैम्ब्डा का उपयोग करने की भी सिफारिश करता है। मैं इस भावना से सहमत हूं। लैम्ब्डा का उपयोग करने से एक बालक अधिक संक्षिप्त लगता है, और इस तरह के महत्वहीन अंतर के साथ, यह औसत स्थिति में बेहतर विकल्प लगता है।
रूबी 1.9 के लिए के रूप में, माफ करना, मैं 1.9 में अभी तक नहीं देखा है, लेकिन मुझे नहीं लगता कि वे इसे इतना सब बदल देंगे (हालांकि इसके लिए अपना शब्द नहीं लेते हैं, ऐसा लगता है कि आपने कुछ बदलावों के बारे में सुना है, इसलिए मैं शायद वहां गलत हूं)।
प्रोक अधिक पुराना है, लेकिन वापसी का शब्दार्थ मेरे लिए अत्यधिक उल्टा है (कम से कम जब मैं भाषा सीख रहा था) क्योंकि:
लैम्ब्डा कार्यात्मक रूप से सुरक्षित है और इसके बारे में तर्क करना आसान है - मैं हमेशा खरीद के बजाय इसका उपयोग करता हूं।
मैं सूक्ष्म अंतर के बारे में ज्यादा नहीं कह सकता। हालांकि, मैं यह बता सकता हूं कि रूबी 1.9 अब लंबोदा और ब्लॉकों के लिए वैकल्पिक मापदंडों की अनुमति देता है।
यहाँ 1.9 के तहत छुरा लैंबडास के लिए नया वाक्यविन्यास है:
stabby = ->(msg='inside the stabby lambda') { puts msg }
रूबी 1.8 में वह वाक्य रचना नहीं थी। न तो ब्लॉक घोषित करने का पारंपरिक तरीका / लैंबडास वैकल्पिक वैकल्पिक समर्थन का समर्थन करता है:
# under 1.8
l = lambda { |msg = 'inside the stabby lambda'| puts msg }
SyntaxError: compile error
(irb):1: syntax error, unexpected '=', expecting tCOLON2 or '[' or '.'
l = lambda { |msg = 'inside the stabby lambda'| puts msg }
रूबी 1.9, हालांकि, पुराने सिंटैक्स के साथ वैकल्पिक तर्कों का भी समर्थन करती है:
l = lambda { |msg = 'inside the regular lambda'| puts msg }
#=> #<Proc:0x0e5dbc@(irb):1 (lambda)>
l.call
#=> inside the regular lambda
l.call('jeez')
#=> jeez
यदि आप तेंदुए या लिनक्स के लिए Ruby1.9 का निर्माण करना चाहते हैं, तो इस लेख को देखें (बेशर्म आत्म प्रचार)।
संक्षिप्त उत्तर: क्या मायने रखता है return
: लैम्ब्डा खुद से बाहर लौटता है, और खुद को और उस फ़ंक्शन को कॉल करता है जो इसे वापस करता है।
क्या कम स्पष्ट है आप प्रत्येक का उपयोग क्यों करना चाहते हैं। लैम्ब्डा वह है जो हम उम्मीद करते हैं कि चीजों को एक कार्यात्मक प्रोग्रामिंग अर्थ में करना चाहिए। यह मूल रूप से मौजूदा दायरे के साथ एक अनाम विधि है जो स्वचालित रूप से बाध्य है। दो में से, लैम्ब्डा वह है जिसका आपको संभवतः उपयोग करना चाहिए।
दूसरी ओर, प्रोक भाषा को लागू करने के लिए वास्तव में उपयोगी है। उदाहरण के लिए आप "यदि" कथन या "उनके साथ" छोरों के लिए लागू कर सकते हैं। प्रॉप में पाया गया कोई भी रिटर्न उस विधि से वापस आ जाएगा जिसने इसे कहा था, न कि केवल "यदि" कथन। यह है कि भाषाएं कैसे काम करती हैं, कैसे "यदि" कथन काम करते हैं, तो मेरा अनुमान है कि रूबी कवर के तहत इसका उपयोग करती है और उन्होंने इसे केवल इसलिए उजागर किया क्योंकि यह शक्तिशाली लग रहा था।
आपको वास्तव में इसकी आवश्यकता तभी होगी जब आप नए भाषा निर्माण जैसे लूप, इफ-कंस्ट्रक्शन आदि का निर्माण कर रहे हों।
इसे देखने का एक अच्छा तरीका यह है कि लैम्ब्डा को अपने दायरे में निष्पादित किया जाता है (जैसे कि यह एक विधि कॉल था), जबकि प्रोक्स को कॉलिंग विधि के साथ इनलाइन निष्पादित के रूप में देखा जा सकता है, कम से कम यह एक अच्छा तरीका है जो विच का उपयोग करने का निर्णय लेता है प्रत्येक मामले में।
मैंने तीसरी विधि में किसी भी टिप्पणी पर ध्यान नहीं दिया, "proc" जो कि पदावनत है, लेकिन 1.8 और 1.9 में अलग तरीके से संभाला गया है।
यहां एक काफी वर्बोज़ उदाहरण दिया गया है जो तीन समान कॉल के बीच के अंतर को देखना आसान बनाता है:
def meth1
puts "method start"
pr = lambda { return }
pr.call
puts "method end"
end
def meth2
puts "method start"
pr = Proc.new { return }
pr.call
puts "method end"
end
def meth3
puts "method start"
pr = proc { return }
pr.call
puts "method end"
end
puts "Using lambda"
meth1
puts "--------"
puts "using Proc.new"
meth2
puts "--------"
puts "using proc"
meth3
proc
1.8 में एक मेमना लौटा; अब 1.9 में एक खरीद वापस करने के लिए तय किया गया है - हालांकि यह एक परिवर्तन है; इसलिए अब उपयोग करने की अनुशंसा नहीं की गई
रूबी में क्लोजर रूबी के साथ ब्लॉक, लैम्ब्डा और प्रोक में काम करने के लिए एक अच्छा अवलोकन है।
लैम्ब्डा अन्य भाषाओं की तरह अपेक्षा के अनुरूप काम करता है।
तार Proc.new
आश्चर्यचकित और भ्रमित है।
return
के द्वारा बनाई गई proc में बयान Proc.new
केवल अभी से ही नियंत्रण वापस नहीं होगा, लेकिन यह enclosing विधि से भी ।
def some_method
myproc = Proc.new {return "End."}
myproc.call
# Any code below will not get executed!
# ...
end
आप तर्क दे सकते हैं कि Proc.new
कोड को ब्लॉक की तरह एन्क्लोजिंग विधि में सम्मिलित करता है। लेकिन Proc.new
एक ऑब्जेक्ट बनाता है, जबकि ब्लॉक एक ऑब्जेक्ट का हिस्सा है ।
और लैम्ब्डा और के बीच एक और अंतर है Proc.new
, जो उनके (गलत) तर्कों को संभालने का है। लैम्ब्डा इसके बारे में शिकायत करता है, जबकि Proc.new
अतिरिक्त तर्कों की अनदेखी करता है या तर्कों के अभाव को शून्य मानता है।
irb(main):021:0> l = -> (x) { x.to_s }
=> #<Proc:0x8b63750@(irb):21 (lambda)>
irb(main):022:0> p = Proc.new { |x| x.to_s}
=> #<Proc:0x8b59494@(irb):22>
irb(main):025:0> l.call
ArgumentError: wrong number of arguments (0 for 1)
from (irb):21:in `block in irb_binding'
from (irb):25:in `call'
from (irb):25
from /usr/bin/irb:11:in `<main>'
irb(main):026:0> p.call
=> ""
irb(main):049:0> l.call 1, 2
ArgumentError: wrong number of arguments (2 for 1)
from (irb):47:in `block in irb_binding'
from (irb):49:in `call'
from (irb):49
from /usr/bin/irb:11:in `<main>'
irb(main):050:0> p.call 1, 2
=> "1"
बीटीडब्ल्यू, proc
रूबी 1.8 में लैम्बडा बनाता है, जबकि रूबी में 1.9+ ऐसा व्यवहार करता है Proc.new
, जो वास्तव में भ्रामक है।
एकॉर्डियन गाय की प्रतिक्रिया के बारे में विस्तार से बताने के लिए:
नोटिस जो Proc.new
एक ब्लॉक को पारित करके एक खरीद बनाता है। मेरा मानना है कि lambda {...}
एक विधि कॉल के बजाय, जो एक ब्लॉक से गुजरता है, एक प्रकार के शाब्दिक के रूप में पार्स किया जाता है। return
एक विधि कॉल से जुड़े ब्लॉक के अंदर से विधि से वापस आ जाएगी, न कि ब्लॉक से, और इस Proc.new
मामले में खेलने का एक उदाहरण है।
(यह 1.8 है। मुझे नहीं पता कि यह 1.9 में कैसे अनुवाद करता है।)
मुझे इस पर थोड़ी देर हो गई है, लेकिन Proc.new
टिप्पणियों में उल्लेख नहीं किए जाने के बारे में एक महान लेकिन छोटी ज्ञात चीज है । द्वारा के रूप में प्रलेखन :
Proc::new
केवल एक ब्लॉक के साथ एक ब्लॉक के बिना एक संलग्न ब्लॉक के साथ एक विधि के बिना बुलाया जा सकता है, उस स्थिति में उस ब्लॉक कोProc
ऑब्जेक्ट में बदल दिया जाता है।
कहा कि, Proc.new
तरीकों की पैदावार को चेन करने देता है:
def m1
yield 'Finally!' if block_given?
end
def m2
m1 &Proc.new
end
m2 { |e| puts e }
#⇒ Finally!
&block
तर्क की घोषणा की जाती है def
, लेकिन बिना डीआरजी सूची में ऐसा करने के लिए।
यह जोर देने के लायक है कि return
एक खरीद में lexically संलग्न विधि से लौटा है, अर्थात जिस विधि से खरीदारी की गई थी , वह विधि नहीं है जिसे खरीद कहा जाता है। यह प्रॉक्स की क्लोजर प्रॉपर्टी का नतीजा है। तो निम्न कोड कुछ भी नहीं आउटपुट:
def foo
proc = Proc.new{return}
foobar(proc)
puts 'foo'
end
def foobar(proc)
proc.call
puts 'foobar'
end
foo
हालांकि proc में कार्यान्वित foobar
, उस में बनाया गया था foo
और इसलिए return
बाहर निकलता है foo
, न सिर्फ foobar
। जैसा कि चार्ल्स कैल्डवेल ने ऊपर लिखा है, यह एक GOTO महसूस करता है। मेरी राय में, return
एक ऐसे ब्लॉक में ठीक है जिसे इसके शाब्दिक संदर्भ में निष्पादित किया जाता है, लेकिन एक अलग संदर्भ में निष्पादित होने वाले किसी प्रोक में उपयोग किए जाने पर बहुत कम सहज है।
return
IMHO के साथ व्यवहार में अंतर 2 के बीच सबसे महत्वपूर्ण अंतर है। मैं लैंबडा को भी पसंद करता हूं क्योंकि यह प्रोटॉन्यू की तुलना में कम टाइपिंग है :-)
proc {}
। मुझे यकीन नहीं है कि यह कब लागू हुआ, लेकिन यह आदि को टाइप करने की तुलना में थोड़ा (आसान) है।