রুবিতে প্রাক এবং ল্যাম্বদার মধ্যে পার্থক্য কী?


176

এবং আপনি কখন অন্যটির চেয়ে একটি ব্যবহার করবেন?


জেটব্যান্ডেসের উত্তর ছাড়াও, returnবিবৃতিটি procবনাম থেকে কী ফিরে আসে তার মধ্যেও পার্থক্য রয়েছে lambda
কেন ব্লুম


2
এখানে আরও বিশদ উত্তর দেওয়া হয়েছে: স্ট্যাকওভারফ্লো.com
ড্যান কে কে

উত্তর:


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
লাম্বডাস অনেকটা পদ্ধতির মতো (আর্গুমেন্টগুলি পরীক্ষা করুন এবং তাদের কাছ থেকে ফিরে আসবে) যখন সঠিকভাবে বলা হয় তবে প্রোকগুলি অনেকগুলি ব্লকের মতো (আর্গুমেন্টগুলি চেক করা হয় না এবং এতে থাকা পদ্ধতি বা ল্যাম্বদা থেকে কোনও রিটার্ন ফিরে আসবে)?
পেডজ

আমি Godশ্বরের কাছে এসেছি এখন অবধি কতগুলি ওয়েবসাইট এবং নিবন্ধ রয়েছে এবং প্রোকস বনাম পদ্ধতি বনাম ল্যাম্বডাসের ইউটিলিটি সম্পর্কে কেউ কথা বলে মনে হচ্ছে না। প্রতিটি ব্যাখ্যা কেবল রিটার্নের মান ইত্যাদি কীভাবে আলাদা হয় তার একটি চুল বিভাজনকারী বিশদ সরবরাহ করে তবে কেন এটি গুরুত্বপূর্ণ তা নিয়ে কিছুই নয়। আপাতত আমাকে এই সিদ্ধান্তে পৌঁছাতে হবে যে এটি রুবিতে একটি ডিজাইনের জগাখিচুড়ি।
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ফিরে আসে, কলিং পদ্ধতিতে ফিরে না গিয়ে তা তাত্ক্ষণিকভাবে এটি করে does

এটি কীভাবে কাজ করে তা দেখতে নীচের কোডটি একবার দেখুন। আমাদের প্রথম পদ্ধতিটি কল করে proc; দ্বিতীয় কল a 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           

প্রকস এবং ল্যাম্বডাসের মধ্যে পার্থক্য

প্রোকস এবং ল্যাম্বডাসের মধ্যে পার্থক্যের মধ্যে যাওয়ার আগে, এটি উল্লেখ করা গুরুত্বপূর্ণ যে তারা উভয় প্রোক অবজেক্ট।

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)

বিপরীতে, প্রক্সগুলি সেটিকে তত্ক্ষণাত ভুল সংখ্যায় পাস করা হয় না care

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 }
lacostenycoder

1

এটি বোঝার আরও একটি উপায় এখানে।

একটি ব্লক হ'ল কোডের একটি অংশ যা কোনও বস্তুর কোনও পদ্ধতির কলটিতে ডাকে। নীচের উদাহরণে স্ব স্ব হ'ল একটি বেনাম শ্রেণীর একশন ভিউ :: বেইস অফ দ্য রেল ফ্রেমওয়ার্কে উত্তরাধিকার সূত্রে (যার মধ্যে নিজেই অনেক সহায়ক মডিউল অন্তর্ভুক্ত)। কার্ড হ'ল এমন একটি পদ্ধতি যা আমরা স্ব স্ব কল করি। আমরা পদ্ধতিতে একটি যুক্তিতে পাস করি এবং তারপরে আমরা সর্বদা পদ্ধতিটির অনুরোধের শেষে ব্লকটি সংযুক্ত করি:

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

উপরের পদ্ধতিতে, পদ্ধতিটিতে পাস করা ব্লকটিকে & একটি রূপান্তর করে একটি বস্তুতে এবং সেই বস্তুকে স্থানীয় ভেরিয়েবল ব্লকে সংরক্ষণ করে। আসলে, আমরা এটি দেখতে পারি যে এটির ল্যাম্বদা এবং প্রোকনউয়ের মতো একই আচরণ রয়েছে:

def add(&block)
  block
end

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

এটা গুরুত্বপূর্ণ. আপনি যখন কোনও পদ্ধতিতে কোনও ব্লক পাস করেন এবং & এর সাহায্যে রূপান্তর করেন, এটি তৈরি করা অবজেক্টটি রূপান্তরটি করতে Proc.new ব্যবহার করে।

নোট করুন যে আমি বিকল্প হিসাবে "প্রোক" ব্যবহার এড়ানো করেছি। এর কারণ এটি রুবি ১.৮, এটি ল্যাম্বদা এবং রুবি ১.৯-তে একই, এটি প্রোক.নেউ এর সমান এবং সমস্ত রুবি সংস্করণে এটি এড়ানো উচিত।

তাহলে আপনি জিজ্ঞাসা করুন ল্যাম্বদা এবং প্রোক.নিউয়ের মধ্যে পার্থক্য কী?

প্রথমত, পরামিতি পাসের ক্ষেত্রে, ল্যাম্বদা একটি পদ্ধতির কলের মতো আচরণ করে। আপনি যদি যুক্তিগুলির ভুল সংখ্যাটি পাস করেন তবে এটি ব্যতিক্রম করবে raise বিপরীতে, 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 + 

দ্বিতীয়ত, ল্যাম্বডা এবং প্রোকন.ইউ রিটার্ন কীওয়ার্ডটি আলাদাভাবে পরিচালনা করে handle আপনি যখন 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"

তাহলে কেন এই আচরণগত পার্থক্য? কারণটি হ'ল প্রোক.নেইউ দিয়ে আমরা ঘেরের পদ্ধতিগুলি প্রসঙ্গে অভ্যন্তরগুলি ব্যবহার করতে পারি এবং যৌক্তিক সিদ্ধান্তগুলি আঁকতে পারি। এই উদাহরণটি দেখুন:

> 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

আমরা প্রত্যাশা করি যে আমরা যখন পুনরাবৃত্তির অভ্যন্তরে ফিরে আসার অনুরোধ করব তখন এটি ঘেরের পদ্ধতি থেকে ফিরে আসবে। মনে রাখবেন যে পুনরাবৃত্তকারীগুলিতে পাস করা ব্লকগুলি প্রোক.নিউ ব্যবহার করে অবজেক্টে রূপান্তরিত হয় এবং সে কারণেই আমরা যখন রিটার্ন ব্যবহার করি, এটি এনকোলেজিং পদ্ধতি থেকে প্রস্থান করবে।

আপনি ল্যাম্বডাসকে বেনামী পদ্ধতি হিসাবে ভাবতে পারেন, তারা কোডের স্বতন্ত্র ব্লকগুলিকে এমন কোনও বস্তুর মধ্যে আলাদা করে রাখে যা কোনও পদ্ধতির মতো চিকিত্সা করা যেতে পারে। শেষ পর্যন্ত, একটি ল্যাম্বডাকে একটি অ্যানোমিয়াস পদ্ধতি হিসাবে আচরণ হিসাবে ভাবেন এবং প্রোল.নেইন ইনলাইন কোড হিসাবে আচরণ করছেন।


0

রুবি গাইড সম্পর্কিত সহায়ক পোস্ট: ব্লক, প্রস এবং ল্যাম্বডাস

প্রকস বর্তমান পদ্ধতি থেকে ফিরে আসে, এবং ল্যাম্বডাস নিজেই ল্যাম্বদা থেকে ফিরে আসে।

প্রকস সঠিক যুক্তির সঠিক সংখ্যা সম্পর্কে চিন্তা করে না, এবং ল্যাম্বডাস একটি ব্যতিক্রম উত্থাপন করবে।


-3

প্রোম এবং ল্যাম্বদার মধ্যে পার্থক্য হ'ল প্রোক হ'ল পরিবর্তনের পরিবর্তে যুক্তিযুক্ত কোডের একটি অনুলিপি, যখন ল্যাম্বডা অন্যান্য ভাষার মতো ফাংশন। (ফেরতের আচরণ, আর্গুমেন্ট চেক)

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.