Wenn Lambda zu verwenden, wenn Proc.new zu benutzen?

stimmen
316

In Ruby 1.8 gibt es feine Unterschiede zwischen proc / Lambda auf der einen Seite und Proc.newauf der anderen Seite .

  • Was sind die Unterschiede?
  • Können Sie Richtlinien geben, wie, welche man wählen entscheiden?
  • In Ruby 1.9 proc und Lambda sind unterschiedlich. Was ist das Problem?
Veröffentlicht am 03/08/2008 um 07:40
quelle vom benutzer
In anderen Sprachen...                            


15 antworten

stimmen
364

Ein weiterer wichtiger , aber feiner Unterschied zwischen Procs erstellt mit lambdaund Procs erstellt mit Proc.new, wie sie der Griff - returnAnweisung:

  • In einem lambda-created proc, die returngibt Anweisung nur aus dem proc selbst
  • In einem Proc.new-created proc, das returnist Aussage ein wenig überraschend: es die Kontrolle nicht nur aus dem proc zurückgibt, sondern auch aus dem Verfahren umschließt das proc!

Hier ist lambda-created proc ist returnin Aktion. Es verhält sich in einer Weise , dass Sie wahrscheinlich erwarten:

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"

Jetzt ist hier ein Proc.new-created proc ist returndas gleiche tun. Sie sind dabei einer der Fälle , zu sehen , wo Ruby den vielgerühmten Prinzip der geringsten Überraschung bricht:

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"

Dank dieses überraschenden Verhalten (wie auch weniger Typisierung), neige ich dazu , mit zu begünstigen lambdaüber , Proc.newwenn Procs zu machen.

Beantwortet am 03/08/2008 um 16:21
quelle vom benutzer

stimmen
93

Zur weiteren Klarstellung:

Joey sagt , dass die Rückkehr Verhalten Proc.newüberraschend. Allerdings , wenn man bedenkt , dass Proc.new wie ein Block verhält sich dies nicht überraschend ist , wie das genau ist , wie Blöcke verhalten. lambas auf der anderen Seite eher wie Methoden verhalten.

Dies erklärt, warum eigentlich Procs flexibel, wenn es um arity (Anzahl der Argumente) kommt während lambda nicht. Blöcke erfordern nicht alle ihre Argumente zur Verfügung gestellt werden, sondern Methoden tun (es sei denn, ein Standard zur Verfügung gestellt). Während der Bereitstellung von Standard-Lambda-Argumente keine Option in Ruby 1.8 ist, ist es nun in Ruby 1.9 mit der alternativen lambda Syntax unterstützt (wie durch webmat vermerkt):

concat = ->(a, b=2){ "#{a}#{b}" }
concat.call(4,5) # => "45"
concat.call(1)   # => "12"

Und Michiel de Mare (die OP) ist falsch über die Procs und Lambda gleich mit arity in Ruby 1.9 verhält. Ich habe festgestellt, dass sie noch das Verhalten von 1,8 aufrechtzuerhalten, wie oben angegeben.

breakAussagen eigentlich nicht viel Sinn in entweder Procs oder lambdas machen. In Procs, würde die Pause kehren Sie von Proc.new, die bereits abgeschlossen ist. Und es macht keinen Sinn aus einem Lambda zu brechen, da es im Wesentlichen eine Methode, und man würde nie von der obersten Ebene eines Verfahren brechen.

next, redoUnd raisedie gleichen beide in Procs und Lambda verhalten. Während retrynicht in entweder erlaubt und wird eine Ausnahme ausgelöst.

Und schließlich das procsollte Verfahren nicht verwendet werden , da es inkonsequent ist und unerwartetes Verhalten hat. In Ruby 1.8 gibt es tatsächlich eine Lambda! In Ruby 1.9 Dieses Problem wurde behoben und es gibt einen Proc. Wenn Sie einen Proc erstellen möchten, bleiben Proc.new.

Für weitere Informationen empfehlen O'Reillys ich sehr mit der Programmiersprache Ruby , die meine Quelle für die meisten dieser Informationen ist.

Beantwortet am 04/10/2009 um 06:23
quelle vom benutzer

stimmen
41

Ich fand diese Seite , die zeigt , was der Unterschied zwischen Proc.newund lambdasind. Laut der Seite, ist der einzige Unterschied , dass eine Lambda über die Anzahl der Argumente streng ist es akzeptiert, während Proc.newKonvertiten Argumente zu fehlen nil. Hier ist ein Beispiel IRB - Sitzung , welche die Differenz:

IRB (Haupt): 001: 0> l = lambda {| x, y | x + y}
=> # <Proc: 0x00007fc605ec0748 @ (rb): 1>
IRB (Haupt): 002: 0> p = Proc.new {| x, y | x + y}
=> # <Proc: 0x00007fc605ea8698 @ (rb): 2>
irb (main): 003: 0> l.call "Hallo", "Welt"
=> "Hello World"
irb (main): 004: 0> p.call "Hallo", "Welt"
=> "Hello World"
irb (main): 005: 0> l.call "Hallo"
Argument: falsche Anzahl von Argumenten (1 2)
    aus (IRB): 1
    von (rb): 5: in `Call‘
    aus (IRB): 5
    von: 0
irb (main): 006: 0> p.call "Hallo"
Typeerror: Konvertierung Null in String
    von (rb): 2: in `+‘
    aus (IRB): 2
    von (rb): 6: in `Call‘
    aus (IRB): 6
    von: 0

Die Seite empfiehlt auch Lambda verwenden, wenn Sie speziell die fehlertolerante Verhalten wollen. Ich stimme mit diesem Gefühl. eine Lambda unter Verwendung scheint ein bisschen mehr prägnant, und mit einer solchen unbedeutenden Unterschied, so scheint es die bessere Wahl in der mittleren Lage.

Wie für Ruby 1.9, sorry, ich habe in 1.9 noch nicht sah, aber ich glaube nicht, würden sie es allzu viel ändern (Sie mein Wort, obwohl es nicht nehmen, es scheint, Sie haben einige Änderungen gehört, so ich bin wahrscheinlich falsch dort).

Beantwortet am 03/08/2008 um 08:28
quelle vom benutzer

stimmen
14

Proc ist schon älter, aber die Semantik der Rückkehr sind mir sehr eingängig (zumindest, wenn ich die Sprache lernte), weil:

  1. Wenn Sie proc verwenden, werden Sie wahrscheinlich eine Art von funktionalen Paradigma.
  2. Proc kann aus dem umschließenden Umfang zurück (siehe vorherige Antworten), die eine im Wesentlichen goto ist und in hohem Maße nicht-funktionelle Natur.

Lambda ist funktional sicherer und einfacher über die Vernunft - ich habe es immer statt proc verwenden.

Beantwortet am 11/09/2008 um 00:32
quelle vom benutzer

stimmen
11

Ich kann nicht viel sagen über die feinen Unterschiede. Allerdings kann ich darauf hinweisen, dass Ruby 1.9 jetzt optionale Parameter für Lambda-Ausdrücke und blockiert werden kann.

Hier ist die neue Syntax für die stabby lambdas unter 1,9:

stabby = ->(msg='inside the stabby lambda') { puts msg }

Ruby 1.8 nicht haben, dass Syntax. Ebenso wenig wie die herkömmliche Art und Weise Blöcke deklarieren / lambdas unterstützen optional argumente:

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

Ruby 1.9 unterstützt jedoch optionale Argumente auch mit der alten Syntax:

l = lambda { |msg = 'inside the regular lambda'|  puts msg }
#=> #<Proc:0x0e5dbc@(irb):1 (lambda)>
l.call
#=> inside the regular lambda
l.call('jeez')
#=> jeez

Wenn Sie ruby1.9 für Leopard oder Linux will bauen, überprüfen Sie diesen Artikel (schamlose Eigenwerbung).

Beantwortet am 19/11/2008 um 22:28
quelle vom benutzer

stimmen
10

Kurze Antwort: Was zählt , ist , was returntut: Lambda kehrt aus sich heraus, und proc Erträge aus selbst und die Funktion , die sie aufgerufen.

Was ist weniger klar ist, warum Sie jede verwenden möchten. Lambda ist das, was wir erwarten, die Dinge in einem funktionalen Programmierung Sinn machen sollte. Es ist im Grunde eine anonyme Methode mit dem aktuellen Bereich automatisch gebunden. Von den beiden Lambda ist derjenige, sollten Sie wahrscheinlich verwenden werden.

Proc, auf der anderen Seite, ist sehr nützlich für die Umsetzung der Sprache selbst. Sie können zum Beispiel „if“ Anweisungen oder „für“ Schleifen mit ihnen umzusetzen. Jede Rückkehr in den proc gefunden wird wieder aus dem Verfahren, die sie aufgerufen, nicht die nur die „if“ Anweisung. Dies ist, wie Sprachen funktionieren, wie „if“ Anweisungen arbeiten, so meine Vermutung ist Rubin verwendet diese unter der Decke und sie es nur ausgesetzt, weil es mächtig zu sein schien.

Sie würden dies nur wirklich brauchen, wenn Sie neue Sprachkonstrukte wie Schleifen zu schaffen sind, if-else-Konstrukte, usw.

Beantwortet am 06/10/2011 um 19:33
quelle vom benutzer

stimmen
9

Ein guter Weg, um es zu sehen ist, dass Lambda-Ausdrücke in ihrem eigenen Umfang ausgeführt werden (als ob es einen Methodenaufruf war), während Procs Inline mindestens so ausgeführt betrachtet werden kann, mit dem anrufenden Verfahren, das ist ein guter Weg, weicht eine, zu entscheiden, zu verwenden in jedem Fall.

Beantwortet am 09/12/2008 um 15:17
quelle vom benutzer

stimmen
8

Ich habe nicht bemerkt, keine Kommentare zu dem dritten Verfahren in dem queston „proc“, die veraltet ist, aber unterschiedlich in 1.8 und 1.9 behandelt.

Hier ist ein ziemlich ausführliches Beispiel, dass es leicht zu sehen, die Unterschiede zwischen den drei ähnlichen Anrufen macht:

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
Beantwortet am 25/06/2009 um 12:22
quelle vom benutzer

stimmen
7

Closures in Ruby ist eine gute Übersicht, wie Blöcke, Lambda und proc Arbeit in Ruby, Ruby.

Beantwortet am 28/08/2008 um 14:50
quelle vom benutzer

stimmen
6

Ruby - Blöcke, Procs und Lambda Verstehen von Robert Sosinski klar erklärt diese Programmierung Konzepte und verstärkt die Erklärungen mit Beispiel - Code. Method - Objekte beziehen und wie gut abgedeckt.

Beantwortet am 23/08/2013 um 18:07
quelle vom benutzer

stimmen
5

Lambda wie erwartet funktioniert, wie in anderen Sprachen.

Die verdrahtet Proc.newist überraschend und verwirrend.

Die returnAussage in proc erstellt von Proc.newwird nicht nur die Kontrolle zurückkehrt nur von mir selbst, sondern auch aus dem Verfahren zu umschließen .

def some_method
  myproc = Proc.new {return "End."}
  myproc.call

  # Any code below will not get executed!
  # ...
end

Sie können argumentieren , dass Proc.newCode in die umschließende Methode fügt, wie Block. Aber Proc.newein Objekt erstellt, während der Block sind Teil eines Objekts.

Und es gibt einen weiteren Unterschied zwischen Lambda und Proc.new, was ihre Handhabung ist (falsch) Argumente. Lambda beschwert sich darüber, während Proc.newzusätzliche Argumente ignoriert oder hält das Fehlen von Argumenten als null.

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"

BTW, procin Ruby 1.8 erstellt eine Lambda, während in Ruby 1.9+ wie verhält Proc.new, was wirklich verwirrend ist.

Beantwortet am 29/10/2014 um 16:22
quelle vom benutzer

stimmen
3

Um näher auf Akkordeon Guy Antwort:

Beachten Sie, dass Proc.neweine proc erzeugt, indem ein Block geleitet wird. Ich glaube , dass lambda {...}als eine Art wörtliche analysiert wird, sondern als ein Methodenaufruf , der einen Block geht. returning von innerhalb eines Blocks zu einem Methodenaufruf angebracht wird von dem Verfahren zurückkehren, nicht der Block, und der Proc.newFall , ist ein Beispiel dafür eine Rolle spielen.

(Dies ist 1,8. Ich weiß nicht, wie dies auf 1,9 übersetzt.)

Beantwortet am 07/09/2008 um 03:31
quelle vom benutzer

stimmen
2

Ich bin ein bisschen spät auf diesem, aber es gibt eine große , aber wenig bekannte Sache über Proc.newnicht in Kommentaren erwähnt. Wie durch Dokumentation :

Proc::newkann nur mit einem daran befestigten Block innerhalb eines Verfahrens ohne Block genannt werden, wobei in diesem Fall , dass Block zum umgewandelt wirdProc Objekt.

Das heißt, Proc.newlässt der Kette Nachgeben Methoden:

def m1
  yield 'Finally!' if block_given?
end

def m2
  m1 &Proc.new
end

m2 { |e| puts e } 
#⇒ Finally!
Beantwortet am 28/04/2015 um 13:15
quelle vom benutzer

stimmen
1

Es ist erwähnenswert , dass Betonung returnin einem proc kehrt von der lexikalisch einschließe Methode, dh das Verfahren , bei dem das proc erstellt wurde , nicht die Methode, die das proc genannt. Dies ist eine Folge der Schließung Eigenschaft Procs. So ist der folgende Code gibt nichts:

def foo
  proc = Proc.new{return}
  foobar(proc)
  puts 'foo'
end

def foobar(proc)
  proc.call
  puts 'foobar'
end

foo

Obwohl die proc in ausführt foobar, wurde erstellt , um in foound um die returnAusgänge foo, nicht nur foobar. Wie Charles Caldwell oben geschrieben habe, hat es ein GOTO spüren. Meiner Meinung nach , returnist in einem Block in Ordnung , die in ihrem lexikalischen Kontext ausgeführt wird, ist aber viel weniger intuitiv , wenn in einem proc verwendet , die in einem anderen Kontext ausgeführt wird.

Beantwortet am 15/11/2018 um 10:00
quelle vom benutzer

stimmen
1

Der Unterschied im Verhalten returnist meiner Meinung nach der wichtigste Unterschied zwischen dem 2. Ich ziehe Lambda auch , weil es weniger tippen als Proc.new :-)

Beantwortet am 11/08/2008 um 03:09
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more