Quand utiliser lambda, quand utiliser Proc.new?

Dans ruby 1.8, il existe des différences subtiles entre proc / lambda d'une part, et Proc.new d'autre part.

  • Quelles sont ces différences?
  • Pouvez-vous donner des lignes directrices sur la façon de décider lequel choisir?
  • Dans ruby 1.9, proc et lambda sont différents. Quel est le problème?
0
ajouté édité
Vues: 2
vous avez accepté la réponse qui dit seulement quelle est la différence entre proc et lambda, alors que le titre de votre question est quand utiliser ces choses
ajouté l'auteur Shri, source
Voir aussi: le livre Langage de programmation ruby de Matz et Flanagan, il a complètement couvert ce sujet. proc se comporte comme une sémantique de bloc - rendement, où lambda se comporte comme une méthode - méthode sémantique d 'appel. Aussi retour, pause, et. tous se comportent diff à procs n lambdas
ajouté l'auteur Gishu, source
Il n'est pas recommandé d'utiliser CEWP dans le site de publication pour plusieurs raisons, par exemple, il stocke les URL en tant qu'URL absolues, n'a pas d'historique des versions, etc. en savoir plus sur andrewconnell.com/blog/archive/2009/02/01/& hellip;
ajouté l'auteur Greg, source
Je n'avais pas entendu ça auparavant, mais c'est logique. Cet effort était l'un de ceux où nous avons essayé de prendre des raccourcis. Peu de temps après ce post, nous avons supprimé ce chemin et avons décidé de développer une mise en page spécifique aux catégories au lieu d'utiliser les pages de vue.
ajouté l'auteur Daemin, source
Voir aussi un article détaillé sur Contrôler les différences de flux entre ruby Procs et Lambdas
ajouté l'auteur Akshay Rawat, source

13 Réponses

Essayez de le vérifier en utilisant SP Designer.

2
ajouté
Eh bien ça a marché. C'est très étrange puisque nous n'avions pas eu à le vérifier auparavant pour les 10 autres séries de changements. Puisque les vues n'ont pas d'approbation de contenu, et cela ne peut pas être fait via l'interface, cela ne m'est pas arrivé de le faire en SPD. Merci!
ajouté l'auteur Daemin, source

J'ai trouvé cette page qui montre quelle est la différence entre Proc.new et < le code> lambda est. Selon la page, la seule différence est qu'un lambda est strict quant au nombre d'arguments qu'il accepte, alors que Proc.new convertit les arguments manquants en nil . Voici un exemple de session IRB illustrant la différence:

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
ajouté
Les procs reviennent aussi différemment que les lambdas.
ajouté l'auteur Cam, source
"" "Proc.new convertit les arguments manquants en nil" "" Proc.new ignore aussi les arguments supplémentaires (bien sûr, lambda se plaint de cela avec une erreur).
ajouté l'auteur weakish, source

La différence de comportement avec return est à mon humble avis la différence la plus importante entre les deux. Je préfère aussi lambda parce que c'est moins typé que Proc.new :-)

0
ajouté
Pour mettre à jour: procs peut maintenant être créé en utilisant proc {} . Je ne suis pas sûr quand cela est entré en vigueur, mais c'est (légèrement) plus facile que d'avoir à taper Proc.new.
ajouté l'auteur aceofbassgreg, source

Pour élaborer sur la réponse d'Accordion Guy:

Notez que Proc.new crée un proc en passant un bloc. Je crois que lambda {...} est analysé comme une sorte de littéral plutôt qu'un appel de méthode qui passe un bloc. return ing depuis l'intérieur d'un bloc attaché à un appel de méthode reviendra de la méthode, pas du bloc, et le cas Proc.new en est un exemple.

(Ceci est 1.8 Je ne sais pas comment cela se traduit par 1.9.)

0
ajouté

Je suis un peu en retard à ce sujet, mais il y a un truc génial mais peu connu à propos de Proc.new qui n'est pas mentionné dans les commentaires. Comme par documentation :

Proc :: new peut être appelé sans bloc uniquement dans une méthode avec un bloc attaché, auquel cas ce bloc est converti en Proc objet.

Cela dit, Proc.new permet d'enchaîner les méthodes:

def m1
  yield 'Finally!' if block_given?
end

def m2
  m1 &Proc.new
end

m2 { |e| puts e } 
#? Finally!
0
ajouté
Intéressant, cela revient à déclarer un argument & block dans def , mais sans avoir à le faire dans la liste def arg.
ajouté l'auteur jrochkind, source

Un bon moyen de le voir est que lambdas sont exécutés dans leur propre portée (comme s'il s'agissait d'un appel de méthode), alors que Procs peut être vu comme exécuté en ligne avec la méthode appelante, au moins c'est un bon moyen de décider dans chaque cas.

0
ajouté

Je ne peux pas en dire beaucoup sur les différences subtiles. Cependant, je peux souligner que ruby 1.9 permet maintenant des paramètres optionnels pour les lambdas et les blocs.

Voici la nouvelle syntaxe pour les lambdas stabby sous 1.9:

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

Ruby 1.8 n'avait pas cette syntaxe. La manière conventionnelle de déclarer des blocs / lambdas ne supportait pas non plus les arguments optionnels:

# 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, cependant, supporte les arguments optionnels même avec l'ancienne syntaxe:

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
ajouté
vous ne montrez pas les paramètres par défaut dans les blocs, seulement lambdas
ajouté l'auteur iconoclast, source
Les paramètres optionnels dans lambda étaient très nécessaires, je suis content qu'ils l'aient ajouté en 1.9. Je suppose que les blocs peuvent aussi avoir des paramètres optionnels alors (en 1.9)?
ajouté l'auteur mpd, source

Pour fournir des précisions supplémentaires:

Joey dit que le comportement de retour de Proc.new est surprenant. Cependant, quand vous considérez que Proc.new se comporte comme un bloc, ce n'est pas surprenant, car c'est exactement comme ça que se comportent les blocs. D'autre part, les lambas se comportent davantage comme des méthodes.

Ceci explique en fait pourquoi les procs sont flexibles quand il s'agit d'arité (nombre d'arguments) alors que les lambdas ne le sont pas. Les blocs n'exigent pas que tous leurs arguments soient fournis, mais les méthodes le font (sauf si une valeur par défaut est fournie). Bien que l'argument lambda par défaut ne soit pas une option dans ruby 1.8, il est maintenant supporté dans ruby 1.9 avec la syntaxe lambda alternative (comme indiqué par webmat):

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

Et Michiel de Mare (l'OP) est incorrect à propos des Procs et lambda se comporter de la même manière avec l'arité dans ruby 1.9. J'ai vérifié qu'ils maintiennent toujours le comportement de 1.8 comme spécifié ci-dessus.

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.

Enfin, la méthode proc ne doit jamais être utilisée car elle est incohérente et a un comportement inattendu. En ruby 1.8, il renvoie effectivement un lambda! En ruby 1.9 cela a été corrigé et il retourne un Proc. Si vous voulez créer un Proc, restez avec Proc.new .

Pour plus d'informations, je recommande fortement le Langage de programmation ruby d'O'Reilly, qui est la source de la plupart de ces informations.

0
ajouté
"" "Cependant, quand vous considérez que Proc.new se comporte comme un bloc, cela n'est pas surprenant car c'est exactement comme ça que se comportent les blocs." "" <- block fait partie d'un objet, tandis que Proc.new crée un objet. Les deux lambda et Proc.new crée un objet dont la classe est Proc, pourquoi diff?
ajouté l'auteur weakish, source

Une autre différence importante mais subtile entre procs créé avec lambda et procs créé avec Proc.new est comment ils gèrent l'instruction 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!

Voici lambda -created proc return en action. Il se comporte d'une manière que vous attendez probablement:

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"

Maintenant, voici un Proc.new -created proc return faisant la même chose. Vous êtes sur le point de voir l'un de ces cas où ruby rompt le Principe de la Plus Petite Surprise tant vanté:

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"

Merci à ce comportement surprenant (ainsi que moins de frappe), j'ai tendance à favoriser lambda sur Proc.new lors de la création de procs.

0
ajouté
ajouté l'auteur ma11hew28, source
Je crois qu'une différence majeure est aussi que les Proc ne lancent pas d'erreurs quand vous fournissez des arguments manquants / supplémentaires, alors que lambda s lancera un mauvais nombre d'arguments erreur
ajouté l'auteur Edmund, source
@mattdipasquale Dans mes tests, proc agit comme lambda et pas comme Proc.new en ce qui concerne les instructions de retour. Cela signifie que le doc ruby ​​est inexact.
ajouté l'auteur Kelvin, source
@mattdipasquale Désolé, j'étais à moitié juste. proc agit comme lambda dans 1.8, mais agit comme Proc.new dans 1.9. Voir la réponse de Peter Wagenet.
ajouté l'auteur Kelvin, source
Ensuite, il y a aussi la méthode proc . Est-ce juste un raccourci pour Proc.new ?
ajouté l'auteur panzi, source
Pourquoi ce comportement "surprenant"? Un lambda est une méthode anonyme. Comme c'est une méthode, elle renvoie une valeur, et la méthode qui l'a appelée peut en faire ce qu'elle veut, y compris l'ignorer et retourner une valeur différente. Un Proc est comme coller dans un extrait de code. Cela n'agit pas comme une méthode. Donc, quand un retour se produit dans le Proc , c'est juste une partie du code de la méthode qui l'a appelé.
ajouté l'auteur Arcolye, source
Comme indiqué par Arcolye, "Procs in ruby sont des extraits de code, pas des méthodes". De robertsosinski.com/2008/12/ 21 / & hellip; . Donc, c'est comme si le retour était dans whowouldwin2 lui-même.
ajouté l'auteur Pietro, source

Je n'ai pas remarqué de commentaires sur la troisième méthode dans le queston, "proc" qui est obsolète, mais géré différemment en 1.8 et 1.9.

Voici un exemple assez détaillé qui permet de voir facilement les différences entre les trois appels similaires:

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
ajouté
Je pense que la pioche dit dans une note de bas de page quelque part que proc est effectivement détruit ou quelque chose. Je n'ai pas le numéro de page exact.
ajouté l'auteur dertoni, source
@banister: proc a renvoyé un lambda dans 1.8; il a maintenant été corrigé pour renvoyer un proc en 1.9 - cependant c'est un changement de rupture; donc pas recommandé d'utiliser plus
ajouté l'auteur Gishu, source
Où avez-vous lu que proc était obsolète?
ajouté l'auteur horseyguy, source
Matz avait déclaré qu'il prévoyait de le désapprouver parce qu'il était déroutant d'avoir proc et que Proc.new retournait des résultats différents. En 1.9, ils se comportent de la même façon (proc est un alias de Proc.new). eigenclass.org/hiki/Changes+in+Ruby+1.9#l47
ajouté l'auteur Dave Rapin, source

Réponse courte: Ce qui compte, c'est ce que return fait: lambda retourne de lui-même, et proc retourne de lui-même ET la fonction qui l'a appelé.

Ce qui est moins clair, c'est pourquoi vous voulez utiliser chacun. lambda est ce que nous attendons que les choses devraient faire dans un sens de programmation fonctionnelle. Il s'agit essentiellement d'une méthode anonyme avec la portée actuelle liée automatiquement. Des deux, lambda est celui que vous devriez probablement utiliser.

Proc, d'autre part, est vraiment utile pour la mise en œuvre du langage lui-même. Par exemple, vous pouvez implémenter des instructions "if" ou des boucles "for" avec celles-ci. Tout retour trouvé dans le proc reviendra hors de la méthode qui l'a appelé, pas juste le "if". C'est ainsi que fonctionnent les langages, comment fonctionnent les instructions "si", donc je pense que ruby les utilise sous les couvertures et les expose juste parce qu'elles semblent puissantes.

Vous n'en aurez vraiment besoin que si vous créez de nouvelles constructions de langage comme des boucles, des constructions if-else, etc.

0
ajouté

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
ajouté

lambda fonctionne comme prévu, comme dans d'autres langues.

Le Proc.new câblé est surprenant et déroutant.

L'instruction return dans proc créée par Proc.new retournera non seulement le contrôle de lui-même, mais aussi de la méthode qui l'entoure .

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

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

Vous pouvez argumenter que Proc.new insère du code dans la méthode englobante, tout comme block. Mais Proc.new crée un objet, tandis que block fait partie d'un objet.

Et il y a une autre différence entre lambda et Proc.new , qui est leur manipulation des (faux) arguments. lambda s'en plaint, alors que Proc.new ignore les arguments supplémentaires ou considère l'absence d'arguments comme nulle.

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
ajouté