Soru Ruby'de proc ve lambda arasındaki fark nedir?


Ve diğerini ne zaman kullanırsın?


155
2017-11-16 04:29


Menşei


Jtbandes'in cevabına ek olarak, aynı zamanda return ifadesi proc e karşı lambda. - Ken Bloom
İşte aynı iyi bir blog awaxman11.github.io/blog/2013/08/05/... - Arup Rakshit
İşte daha detaylı cevap: stackoverflow.com/questions/626/... - Dan K.K.


Cevaplar:


Tek fark, argümanları ele alma biçimindedir. Kullanarak bir pro proc {} ve Proc.new {} eşdeğerdir. Ancak, kullanarak lambda {} size geçirilen argümanların sayısını kontrol eden bir proc verir. itibaren ri Kernel#lambda:

Eşittir Proc.newSonuçta ortaya çıkan Proc nesneleri çağrıldığında geçirilen parametre sayısını kontrol eder.

Bir örnek:

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)

Ek olarak, Ken'in dikkat çektiği gibi return bir lambda içinde o lambda değerini döndürür, ama return bir proc içinde kapatma bloğundan döner.

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

Bu nedenle, çoğu hızlı kullanım için aynıdır, ancak otomatik katı argüman kontrolünü (bazen hata ayıklamada da yardımcı olabilir) istiyorsanız ya da return proc değerini döndürmek için deyim, lambda.


235
2017-11-16 04:42



Problar çok benzer bloklar iken (argümanlar kontrol edilmediğinde ve geri dönüş, içerilen yöntem veya lambdadan geri dönecekse) lambdaların yöntemlere çok benzediğini (kontrol argümanlarını ve dönüşleri geri döneceklerini) söylemek doğru olur mu? - pedz


Proses ve lambdas arasındaki gerçek fark, kontrol akışı anahtar kelimeleri ile ilgili her şeye sahiptir. hakkında konuşuyorum return, raise, break, redo, retry vb - bu kontrol kelimeleri. Bir işlemde iade beyannamesinin olduğunu varsayalım. Proc'nuzu aradığınızda, sadece sizi bunun dışında bırakmaz, aynı zamanda kapama yönteminden de döner.

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

Son puts yöntemde, hiçbir zaman, bizim proc çağrıldığında return içinde bizi yöntemden çıkardı. Ancak, proc'muzu lambdaya çevirirsek, aşağıdakileri alırız:

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

Lambda içindeki geri dönüş bizi sadece lambdadan çıkarır ve kapama metodu çalışmaya devam eder. Kontrol akış anahtar kelimelerinin proaktif olarak işleme tabi tutulduğu ve lambdaların aralarındaki temel fark budur.


60
2018-03-24 12:57



en çok oylanandan çok daha iyi - GavinLuo


Bu biraz ince. Her ikisi de kapaklar oluşturan ve her ikisi de Proc nesnelerini döndüren yöntemlerdir. Aslında üçüncü bir yol var - Proc.new. Fark, nasıl davrandıklarıdır ve özellikler, Ruby 1.8 veya 1.9'u kullanıp kullanmadığınıza bağlıdır (aslında, bunları Ruby 1.9'da oluşturmanın bir başka yolu daha vardır). Genel durumda, fark endişelenmen gereken bir şey değildir. Sadece katılıktan endişe duyduğunuzda fark yaratır. Ne zaman lambda, ne zaman Proc.new kullanmak için? farklılıkları çok iyi kapsamaktadır.


3
2017-11-16 04:47





Genel olarak, lambdalar proklardan daha sezgiseldir çünkü onlar yöntemlere daha çok benzer. Onlar ariteyle ilgili oldukça katı ve sadece dönüşü aradığınızda çık. Bu nedenle, birçok Rubyist lambdaları Prometes'in belirli özelliklerine ihtiyaç duymadıkça ilk tercih.

yordamlara: Sınıf nesneleri Proc . Bloklar gibi, kapsamda değerlendirilir tanımlandıkları yer. Lambda'lar: Ayrıca sınıfın nesneleri Proc ama düzenli prosedürlerden farklı bir şekilde farklıdır. Onlar bloklar ve prometler gibi kapanışlardır ve onlar da değerlendirilir tanımladıkları kapsam.

Proc oluşturma

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

Lambda oluşturma

b = lambda { |x| x 2 }


0
2018-05-21 17:39



a = proc { |x| x 2 } aynıdır a = Proc.new { |x| x 2 } - lacostenycoder


Bunu anlamanın başka bir yolu var.

Bir blok, bir nesnede bir yöntemin çağrısına çağrıya eklenmiş bir kod parçasıdır. Aşağıdaki örnekte, kendilik, Rails çerçevesindeki ActionView :: Base'den (kendisi birçok yardımcı modül içerir) gelen bir anonim sınıf örneğidir. Kart, kendimiz çağırdığımız bir yöntemdir. Yönteme bir argüman göndeririz ve daha sonra bloğu her zaman yöntem çağırma işleminin sonuna ekleriz:

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

Tamam, bir kod kodunu bir yönteme aktarıyoruz. Fakat bu bloğu nasıl kullanırız? Bir seçenek, kod parçasını bir nesneye dönüştürmektir. Ruby, bir kod parçasını bir nesneye dönüştürmenin üç yolunu sunar

# 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

Yukarıdaki yöntemde, yönteme geçirilen bloğu bir nesneye dönüştürür ve bu nesneyi yerel değişken bloğunda depolar. Aslında, lambda ve Proc.new ile aynı davranışa sahip olduğunu gösterebiliriz:

def add(&block)
  block
end

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

Bu önemli. Bir yönteme bir bloğu iletip & 'yi kullanarak dönüştürdüğünüzde, oluşturduğu nesne dönüştürmeyi yapmak için Proc.new kullanır.

Bir seçenek olarak "proc" kullanımını engellediğimi unutmayın. Bu Ruby 1.8, lambda ve Ruby 1.9 ile aynıdır, Proc.new ile aynıdır ve tüm Ruby sürümlerinde kaçınılmalıdır.

Öyleyse lambda ve Proc.new arasındaki fark nedir?

İlk olarak, parametre geçişi açısından, lambda bir yöntem çağrısı gibi davranır. Yanlış sayıda argüman iletirseniz bir istisna artacaktır. Aksine, Proc.new paralel atamalar gibi davranır. Kullanılmayan tüm argümanlar nil'e dönüştürülür:

> 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 + 

İkinci olarak, lambda ve Proc.new, dönüş anahtar kelimesini farklı şekilde ele alır. Proc.new içinde bir dönüş yaptığınızda, aslında çevreleyen yöntem, yani çevreleyen bağlamdan döndürür. Bir lambda bloktan döndüğünüzde, sadece kapama yönteminden değil, bloktan döner. Temel olarak, bloğa yapılan çağrıdan çıkar ve kapatma yönteminin geri kalanıyla yürütmeyi sürdürür.

> 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"

Peki neden bu davranışsal fark? Bunun nedeni, Proc.new ile yineleme yöntemlerini, bağlamlama yöntemleri bağlamında kullanabilir ve mantıksal sonuçlar çıkartabiliriz. Şu örneğe bakın:

> 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

Geri çağırdığımızda, yineleyicinin içine geri döndüğümüzde, kapanış yönteminden döneceğini umuyoruz. Yineleyicilerden geçirilen blokları Proc.new kullanarak nesnelere dönüştürüldüğünü unutmayın ve bu yüzden iade kullandığımızda kapsayıcı yöntemden çıkacaktır.

Lambdaları anonim yöntemler olarak düşünebilirsiniz, tek tek kod bloklarını bir yöntem gibi ele alınabilecek bir nesneye ayırırlar. Nihayetinde, bir lambdayı, anormal bir yöntem olarak davranmayı düşünün ve Proc.new, satır içi kod gibi davranın.


0
2018-05-28 01:12





Sadece iki ana farklılık var.

  • Önce lambda kendisine iletilen argümanların sayısını kontrol eder. proc değil. Bu demek ki lambda yanlış argüman sayısını aktarırsanız bir hata verir. proc beklenmedik argümanları yok sayar ve atar nil eksik olanlara.
  • İkincisi, ne zaman lambda döner, denetimi çağrı yöntemine geri geçirir; zaman proc döner, hemen çağrı yöntemine geri dönmeden yapar.

Bunun nasıl çalıştığını görmek için aşağıdaki koda bakın. İlk yöntemimiz bir proc; ikinci bir çağrı 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!"

Nasıl görüyor proc "Batman kazanacak!" diyor, çünkü batman_ironman_proc yöntemine geri dönmeden hemen geri dönüyor.

bizim lambdaAncak, çağrıldıktan sonra yönteme geri döner, böylece yöntem değerlendirdiği son kodu döndürür: "Demir Adam kazanacak!"


0
2017-08-06 13:45





proc ve lambda arasındaki farklar, prod'un argümanların sırayla değiştirildiği bir kod kopyası olması, lambda ise diğer dillerdeki gibi bir fonksiyon olmasıdır. (dönüş davranışları, argümanlar kontrolleri)


-2
2017-11-04 10:54