Vă mulțumim pentru susținere

Când să folosiți lambda, când să folosiți Proc.new?

În Ruby 1.8, există diferențe subtile între proc / lambda pe de o parte și Proc.new pe de altă parte.

  • Care sunt diferențele?
  • Puteți să oferiți indicații despre cum să decideți care dintre ele să alegeți?
  • În Ruby 1.9, proc și lambda sunt diferite. Care-i treaba?
0
adăugat editat
ați acceptat răspunsul care spune doar ce este diferența dintre proc și lambda, în timp ce titlul întrebării dvs. este când să utilizați aceste lucruri
adăugat autor Shri
A se vedea de asemenea: cartea de limbaj de programare Ruby de Matz și Flanagan, a abordat cuprinzător acest subiect. proc se comportă ca o semantică a randamentului blocului, unde lambda se comportă ca o metodă - semantică de apel. De asemenea, reveniți, rupeți, et. toate se comporte diff în procs n lambdas
adăugat autor Gishu
Nu este recomandat să utilizați CEWP în publicarea site-ului din mai multe motive, cum ar fi stocarea adreselor URL ca adrese URL absolute, nu are istoric de versiuni etc., mai multe despre acesta la
adăugat autor Greg
N-am mai auzit asta, dar asta are sens. Acest efort a fost unul dintre cele în care am încercat să facem reduceri. La scurt timp după acest post, am eliminat această cale și am decis să dezvoltăm un aspect specific categoriilor în loc să folosim paginile de vizualizare.
adăugat autor Daemin
adăugat autor Akshay Rawat

13 răspunsuri

Încercați să o verificați utilizând Designer SP.

2
adăugat
Ei bine, a funcționat. Este foarte ciudat, deoarece nu trebuia să verificăm înainte pentru celelalte 10 seturi de schimbări. Deoarece vizualizările nu au aprobare de conținut și nu pot fi realizate prin interfața pe care nu mi-a venit-o să o fac în SPD. Mulțumiri!
adăugat autor Daemin

Am găsit această pagină care arată ce diferență dintre Proc.new și < cod> lambda sunt. Conform paginii, singura diferență este că o lambda este strictă în ceea ce privește numărul de argumente pe care le acceptă, în timp ce Proc.new convertește argumentele lipsă la zero . Iată un exemplu de sesiune IRB care ilustrează diferența:

irb(main):001:0> l = lambda { |x, y| x + y }
=> #
irb(main):002:0> p = Proc.new { |x, y| x + y }
=> #
irb(main):003:0> l.call "hello", "world"
=> "helloworld"
irb(main):004:0> p.call "hello", "world"
=> "helloworld"
irb(main):005:0> l.call "hello"
ArgumentError: wrong number of arguments (1 for 2)
    from (irb):1
    from (irb):5:in `call'
    from (irb):5
    from :0
irb(main):006:0> p.call "hello"
TypeError: can't convert nil into String
    from (irb):2:in `+'
    from (irb):2
    from (irb):6:in `call'
    from (irb):6
    from :0

The page also recommends using lambda unless you specifically want the error tolerant behavior. I agree with this sentiment. Using a lambda seems a tad more concise, and with such an insignificant difference, it seems the better choice in the average situation.

As for Ruby 1.9, sorry, I haven't looked into 1.9 yet, but I don't imagine they would change it all that much (don't take my word for it though, it seems you have heard of some changes, so I am probably wrong there).

0
adăugat
procs se întorc, de asemenea, în mod diferit decât lambda.
adăugat autor Cam
"" "Proc.new convertește argumentele lipsă la zero" "" Proc.new ignoră, de asemenea, argumente suplimentare (desigur, lambda se plânge cu o eroare).
adăugat autor weakish

Diferența de comportament cu return este IMHO cea mai importantă diferență dintre 2. Eu, de asemenea, prefer să lambda pentru că este mai puțin de tipar decât Proc.new :-)

0
adăugat
Pentru a actualiza: procs-ul poate fi acum creat folosind proc {} . Nu sunt sigur când a intrat în vigoare, dar este (ușor) mai ușor decât să trebuiască să tastați Proc.new.
adăugat autor aceofbassgreg

Pentru a elabora răspunsul lui Accordion Guy:

Observați că Proc.new creează o proc ieșire prin trecerea unui bloc. Eu cred că lambda {...} este analizat ca un fel de apel literal, mai degrabă decât de metodă, care trece printr-un bloc. return din interiorul unui bloc atașat la un apel de metodă va reveni din metodă, nu din bloc, iar cazul Proc.new este un exemplu al acestui joc.

(Acesta este 1.8. Nu știu cum se traduce acest lucru la 1.9.)

0
adăugat

Sunt un pic cam târziu, dar există un mare lucru, dar puțin cunoscut despre Proc.new , care nu este menționat în comentarii deloc. Ca și în documentație :

Proc :: new poate fi apelat fără un bloc numai în cadrul unei metode cu un bloc atașat, caz în care blocul este convertit în Proc / strong>.

Acestea fiind spuse, Proc.new permite să lanseze metode de randament:

def m1
  yield 'Finally!' if block_given?
end

def m2
  m1 &Proc.new
end

m2 { |e| puts e } 
#? Finally!
0
adăugat
Interesant, face același lucru cu declanșarea unui argument & block în def , dar fără a fi nevoie să faceți acest lucru în lista def arg.
adăugat autor jrochkind

O modalitate bună de a vedea este că lambda-urile sunt executate în sfera lor de aplicare (ca și cum ar fi fost un apel de metodă), în timp ce Procs poate fi văzut ca executat în linie cu metoda de apelare, cel puțin aceasta este o modalitate bună de a decide cine să folosească in fiecare caz.

0
adăugat

Nu pot spune prea multe despre diferențele subtile. Cu toate acestea, pot să subliniez că Ruby 1.9 permite acum parametrii opționali pentru lambda și blocuri.

Iată noua sintaxă pentru lambda-urile de la sub 1.9:

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

Ruby 1.8 nu avea această sintaxă. Nici modul convențional de declarare a blocurilor / lambdelor nu conține opțiuni opționale:

# 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, cu toate acestea, acceptă argumente opționale chiar și cu vechea sintaxă:

l = lambda { |msg = 'inside the regular lambda'|  puts msg }
#=> #
l.call
#=> inside the regular lambda
l.call('jeez')
#=> jeez

If you wanna build Ruby1.9 for Leopard or Linux, check out this article (shameless self promotion).

0
adăugat
nu demonstrați parametrii impliciți în blocuri, doar lambda
adăugat autor iconoclast
Paramurile opționale din cadrul lambda au fost foarte necesare, mă bucur că l-au adăugat în 1.9. Presupun că blocurile pot avea și parametri opțional atunci (în 1.9)?
adăugat autor mpd

Pentru a oferi clarificări suplimentare:

Joey spune că comportamentul de revenire al Proc.new este surprinzător. Cu toate acestea, atunci când considerați că Proc.new se comportă ca un bloc, acest lucru nu este surprinzător, deoarece exact așa se comportă blocurile. lambas, pe de altă parte, se comportă mai mult ca metodele.

Acest lucru explică de ce Procs sunt flexibile când vine vorba de arity (numărul de argumente), în timp ce lambda nu este. Blocurile nu necesită furnizarea tuturor argumentelor acestora, dar metodele fac (cu excepția cazului în care este furnizată o prestație implicită). În timp ce furnizarea default lambda argument nu este o opțiune în Ruby 1.8, este acum susținută în Ruby 1.9 cu sintaxa lambda alternativă (așa cum a remarcat webmat):

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

Și Michiel de Mare (OP) este incorect în legătură cu Procs și lambda care se comportă la fel cu arity în Ruby 1.9. Am verificat că ei încă mențin comportamentul de la 1.8 așa cum este specificat mai sus.

break statements don't actually make much sense in either Procs or lambdas. In Procs, the break would return you from Proc.new which has already been completed. And it doesn't make any sense to break from a lambda since it's essentially a method, and you would never break from the top level of a method.

next, redo, and raise behave the same in both Procs and lambdas. Whereas retry is not allowed in either and will raise an exception.

În cele din urmă, metoda proc nu ar trebui folosită niciodată deoarece este incoerentă și are un comportament neașteptat. În Ruby 1.8 se întoarce de fapt o lambda! În Ruby 1.9 aceasta a fost rezolvată și ea returnează un Proc. Dacă doriți să creați un Proc, stick cu Proc.new .

Pentru mai multe informații, recomand foarte mult limbajul de programare Ruby al O'Reilly, care este sursa mea pentru majoritatea acestor informații.

0
adăugat
"" Totuși, atunci când considerați că Proc.new se comportă ca un bloc, acest lucru nu este surprinzător, deoarece exact așa se comportă blocurile. "" "<- blocul face parte dintr-un obiect, în timp ce Proc.new creează un obiect. Ambele lambda și Proc.new creează un obiect a cărui clasă este Proc, de ce diff?
adăugat autor weakish

O altă diferență importantă, dar subtilă între procs-urile create cu lambda și procs-urile create cu Proc.new este modul în care se ocupă de instrucțiunea return

  • In a lambda-created proc, the return statement returns only from the proc itself
  • In a Proc.new-created proc, the return statement is a little more surprising: it returns control not just from the proc, but also from the method enclosing the proc!

Iată lambda întocmite în acțiune. Se comportă într-un mod pe care probabil vă așteptați:

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"

Acum, aici este un Proc.new întocmit același lucru. Sunteți pe punctul de a vedea unul dintre acele cazuri în care Ruby încalcă Principiul cel mai puțin surprinzător:

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"

Datorită acestui comportament surprinzător (și mai puțin tastând), am tendința de a favoriza utilizarea lambda peste Proc.new atunci când faceți procs.

0
adăugat
adăugat autor ma11hew28
Cred că o diferență majoră este și faptul că Proc s nu aruncă erori atunci când furnizează argumente lipsă / extra, în timp ce lambda s va arunca un număr < eroare
adăugat autor Edmund
@mattdipasquale În testele mele, proc acționează ca lambda și nu ca Proc.new în ceea ce privește declarațiile de returnare. Asta înseamnă că docul rubin este inexact.
adăugat autor Kelvin
@mattdipasquale Ne pare rău că am fost doar pe jumătate dreapta. proc acționează ca lambda în 1.8, dar acționează ca Proc.new în 1.9. Vedeți răspunsul lui Peter Wagenet.
adăugat autor Kelvin
Apoi, există și metoda proc . Este doar o scurtă însemnă pentru Proc.new ?
adăugat autor panzi
De ce este acest comportament "surprinzător"? Un lambda este o metodă anonimă. Deoarece este o metodă, aceasta returnează o valoare, iar metoda care a numit-o poate face cu orice vrea, inclusiv ignorând-o și returnând o altă valoare. Un Proc este ca și cum ați lipi într-un fragment de cod. Nu se comportă ca o metodă. Deci, atunci când o întoarcere se întâmplă în cadrul Proc , aceasta este doar o parte din codul metodei care o numește.
adăugat autor Arcolye
Așa cum a subliniat Arcolye, "Procs în Ruby sunt drop în fragmente de cod, nu metode". De la robertsosinski.com/2008/12/ 21 / & hellip; . Deci este ca întoarcerea să fie în sine însuși.
adăugat autor Pietro

Nu am observat niciun fel de comentarii cu privire la cea de-a treia metodă din queston, "proc", care este depreciat, dar se ocupă diferit în 1.8 și 1.9.

Iată un exemplu destul de amănunțit care face ușor să vedem diferențele dintre cele trei apeluri similare:

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
0
adăugat
Cred că pickaxe spune într-o notă de subsol undeva că proc este în mod efectiv deprimat sau altceva. Nu am numărul exact al paginii.
adăugat autor dertoni
@banister: proc a returnat o lambda în 1.8; acum a fost fixat să se întoarcă un proc în 1.9 - totuși aceasta este o schimbare de rupere; prin urmare nu se recomandă să mai utilizați
adăugat autor Gishu
unde ați citit că proc a fost depreciat?
adăugat autor horseyguy
Matz a declarat că intenționează să o deprecieze deoarece a fost confuz să aibă proc și Proc.new returnează rezultate diferite. În 1.9 se comportă același lucru (proc este un alias Proc.new). eigenclass.org/hiki/Changes+in+Ruby+1.9#l47
adăugat autor Dave Rapin

Răspuns scurt: ceea ce contează este ceea ce returnează : lambda revine din sine, iar proc întoarce din sine și funcția care o numește.

Ceea ce este mai puțin clar este motivul pentru care doriți să utilizați fiecare. lambda este ceea ce ne așteptăm ca lucrurile să facă într-un sens funcțional de programare. Este, practic, o metodă anonimă, cu domeniul de aplicare actual legat automat. Dintre cele două, lambda este cea pe care ar trebui să o utilizați.

Proc, pe de altă parte, este foarte util pentru implementarea limbii în sine. De exemplu, puteți implementa declarații "dacă" sau "pentru" cu ele. Orice întoarcere găsită în proc se va întoarce din metoda care a numit-o, nu doar declarația "if". Acesta este modul în care funcționează limbile, cum funcționează declarațiile "dacă", așa că presupun că Ruby folosește acest lucru sub capace și tocmai l-au expus deoarece păreau puternice.

Ați avea nevoie de acest lucru doar dacă creați construcții de limbi noi cum ar fi bucle, dacă construiți altfel etc.

0
adăugat

Understanding Ruby Blocks, Procs and Lambdas by Robert Sosinski clearly explains these programming concepts and reinforces the explanations with example code. Method objects are related and covered as well.

0
adăugat

lambda funcționează conform așteptărilor, ca și în alte limbi.

Codul Proc.new cu fir este surprinzător și confuz.

Instrucțiunea return din proc, creată de Proc.new , nu va reveni doar la control, ci și la metoda care îl include .

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

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

Puteți argumenta că Proc.new inserează codul în metoda de închidere, la fel ca blocul. Dar Proc.new creează un obiect, în timp ce blocul este parte a unui obiect.

Și există o altă diferență între lambda și Proc.new , care este manipularea argumentelor (greșite). lambda se plânge de aceasta, în timp ce Proc.new ignoră argumente suplimentare sau consideră lipsa argumentelor ca fiind nulă.

irb(main):021:0> l = -> (x) { x.to_s }
=> #
irb(main):022:0> p = Proc.new { |x| x.to_s}
=> #
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 `
' 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 `
' irb(main):050:0> p.call 1, 2 => "1"

BTW, proc in Ruby 1.8 creates a lambda, while in Ruby 1.9+ behaves like Proc.new, which is really confusing.

0
adăugat