Une différence réside dans la manière dont ils traitent les arguments. Créer un proc en utilisant proc {}et Proc.new {}sont équivalents. Cependant, utiliser lambda {}vous donne un proc qui vérifie le nombre d'arguments qui lui sont passés. De ri Kernel#lambda:
Équivalent à Proc.new , sauf que les objets Proc résultants vérifient le nombre de paramètres transmis lors de l'appel.
Un exemple:
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)
De plus, comme le fait remarquer Ken, utiliser à l' returnintérieur d'un lambda renvoie la valeur de ce lambda, mais utiliser returndans un proc renvoie à partir du bloc englobant.
Donc, pour la plupart des utilisations rapides, ils sont les mêmes, mais si vous voulez une vérification automatique des arguments stricts (qui peut aussi parfois aider au débogage), ou si vous devez utiliser l' returninstruction pour renvoyer la valeur de proc, utilisez lambda.
Serait-il exact de dire que les lambdas ressemblent beaucoup aux méthodes (vérifier les arguments et le retour en reviendra) tandis que les procs ressemblent beaucoup à des blocs (les arguments ne sont pas vérifiés et un retour sera renvoyé de la méthode contenant ou de lambda)?
pedz
Je suis allé à Dieu sait combien de sites Web et d'articles à l'heure actuelle et personne ne semble parler de l'utilité de Procs vs méthodes vs lambdas. Chaque explication fournit simplement un détail époustouflant sur la façon dont les valeurs de retour, etc., sont différentes, mais aucune sur pourquoi cela compte. Pour l'instant, je dois conclure qu'il s'agit d'un désordre de conception dans Ruby.
ankush981 le
76
La vraie différence entre procs et lambdas a tout à voir avec les mots-clés de flux de contrôle. Je parle return, raise, break, redo, retryetc. - ces mots de contrôle. Disons que vous avez une instruction return dans un proc. Lorsque vous appelez votre proc, il vous en sortira non seulement, mais reviendra également de la méthode englobante, par exemple:
Le final putsde la méthode n'a jamais été exécuté, car lorsque nous avons appelé notre proc, celui- returnci nous a vidés de la méthode. Si, cependant, nous convertissons notre proc en lambda, nous obtenons ce qui suit:
def my_method
puts "before proc"
my_proc = lambda do
puts "inside proc"returnend
my_proc.call
puts "after proc"end
my_method
shoaib@shoaib-ubuntu-vm:~/tmp$ ruby a.rb
before proc
inside proc
after proc
Le retour dans le lambda nous vide uniquement du lambda lui-même et la méthode englobante continue de s'exécuter. La façon dont les mots-clés de flux de contrôle sont traités dans les procs et les lambdas est la principale différence entre eux
Tout d'abord, a lambdavérifie le nombre d'arguments qui lui sont passés, proccontrairement à a. Cela signifie que a lambdalancera une erreur si vous lui transmettez un nombre incorrect d'arguments, tandis que a procignorera les arguments inattendus et les assignera nilà ceux qui manquent.
Deuxièmement, quand un lambdaretourne, il repasse le contrôle à la méthode appelante; quand a procrevient, il le fait immédiatement, sans revenir à la méthode appelante.
Pour voir comment cela fonctionne, jetez un œil au code ci-dessous. Notre première méthode appelle a proc; le second appelle 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!"
Voyez comment le procdit "Batman va gagner!", C'est parce qu'il revient immédiatement, sans revenir à la méthode batman_ironman_proc.
Notre lambda, cependant, retourne dans la méthode après avoir été appelée, donc la méthode renvoie le dernier code qu'elle évalue: "Iron Man va gagner!"
1. Lambdas vérifie le nombre d'arguments, alors que procs ne le fait pas
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)
En revanche, les procs ne se soucient pas de savoir s'ils reçoivent un nombre incorrect d'arguments.
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. Lambdas et procs traitent le mot-clé "return" différemment
'return' à l'intérieur d'un lambda déclenche le code juste à l'extérieur du code lambda
Et pour répondre à votre autre question, laquelle utiliser et quand? Je suivrai @jtbandes comme il l'a mentionné
Donc, pour la plupart des utilisations rapides, ils sont les mêmes, mais si vous voulez une vérification automatique des arguments stricts (qui peut aussi parfois aider au débogage), ou si vous devez utiliser l'instruction return pour renvoyer la valeur du proc, utilisez lambda.
De manière générale, les lambdas sont plus intuitives que les procs car elles sont plus similaires aux méthodes. Ils sont assez stricts sur l'arité et ils sortent simplement lorsque vous appelez le retour. Pour cette raison, de nombreux Rubyistes utilisent les lambdas comme premier choix, à moins qu'ils n'aient besoin des fonctionnalités spécifiques de procs.
Procs: objets de classe Proc. Comme les blocs, ils sont évalués dans la portée où ils sont définis.
Lambdas: également des objets de classe Procmais subtilement différents des procs normaux. Ce sont des fermetures comme des blocs et des processus, et en tant que telles, elles sont évaluées dans la portée où elles sont définies.
a = proc { |x| x 2 }est le même quea = Proc.new { |x| x 2 }
lacostenycoder
1
Voici une autre façon de comprendre cela.
Un bloc est un morceau de code attaché à l'appel à un appel d'une méthode sur un objet. Dans l'exemple ci-dessous, self est une instance d'une classe anonyme héritant d'ActionView :: Base dans le framework Rails (qui lui-même comprend de nombreux modules d'assistance). la carte est une méthode que nous appelons nous-mêmes. Nous passons un argument à la méthode puis nous attachons toujours le bloc à la fin de l'appel de la méthode:
self.card :contacts do|c|// a chunk of valid ruby code
end
Ok, donc nous passons un morceau de code à une méthode. Mais comment utiliser ce bloc? Une option consiste à convertir le morceau de code en un objet. Ruby propose trois façons de convertir un morceau de code en objet
# 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 namedef add(&block)end
Dans la méthode ci-dessus, le & convertit le bloc passé à la méthode en un objet et stocke cet objet dans le bloc de variables locales. En fait, nous pouvons montrer qu'il a le même comportement que lambda et Proc.new:
def add(&block)
block
end
l3 = add {|a| a +1}
l3.call(1)=>2
C'est important. Lorsque vous passez un bloc à une méthode et que vous le convertissez à l'aide de &, l'objet qu'il crée utilise Proc.new pour effectuer la conversion.
Notez que j'ai évité d'utiliser "proc" comme option. C'est parce que c'est Ruby 1.8, c'est la même chose que lambda et dans Ruby 1.9, c'est la même chose que Proc.new et dans toutes les versions de Ruby, cela devrait être évité.
Alors vous demandez quelle est la différence entre lambda et Proc.new?
Premièrement, en termes de passage de paramètres, lambda se comporte comme un appel de méthode. Cela lèvera une exception si vous passez le mauvais nombre d'arguments. En revanche, Proc.new se comporte comme une affectation parallèle. Tous les arguments inutilisés sont convertis en nil:
> l = lambda {|a,b| puts "#{a} + #{b}"}=>#<Proc:0x007fbffcb47e40@(irb):19 (lambda)> > l.call(1)ArgumentError: wrong number of arguments (1for2)> l2 =Proc.new {|a,b| puts "#{a} + #{b}"}=>#<Proc:0x007fbffcb261a0@(irb):21> > l2.call(1)1+
Deuxièmement, lambda et Proc.new gèrent le mot clé return différemment. Lorsque vous effectuez un retour à l'intérieur de Proc.new, il retourne en fait à partir de la méthode englobante, c'est-à-dire du contexte environnant. Lorsque vous revenez d'un bloc lambda, il revient simplement du bloc, pas de la méthode englobante. Fondamentalement, il quitte l'appel au bloc et continue l'exécution avec le reste de la méthode englobante.
>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"
Alors pourquoi cette différence de comportement? La raison en est qu'avec Proc.new, nous pouvons utiliser des itérateurs dans le contexte des méthodes englobantes et tirer des conclusions logiques. Regardez cet exemple:
>def print(max)[1,2,3,4,5].each do|val|
puts val
returnif val > max
endend> print(3)1234
Nous nous attendons à ce que lorsque nous invoquons return à l'intérieur de l'itérateur, il revienne de la méthode englobante. N'oubliez pas que les blocs passés aux itérateurs sont convertis en objets à l'aide de Proc.new et c'est pourquoi lorsque nous utilisons return, il quittera la méthode englobante.
Vous pouvez considérer les lambdas comme des méthodes anonymes, elles isolent des blocs de code individuels dans un objet qui peut être traité comme une méthode. En fin de compte, pensez qu'un lambda se comporte comme une méthode anomyous et que Proc.new se comporte comme du code en ligne.
la différence entre proc et lambda est que proc est juste une copie de code avec des arguments remplacés à son tour, tandis que lambda est une fonction comme dans d'autres langages. (comportement de retour, vérification des arguments)
return
déclaration renvoie de parproc
rapport àlambda
.Réponses:
Une différence réside dans la manière dont ils traitent les arguments. Créer un proc en utilisant
proc {}
etProc.new {}
sont équivalents. Cependant, utiliserlambda {}
vous donne un proc qui vérifie le nombre d'arguments qui lui sont passés. Deri Kernel#lambda
:Un exemple:
De plus, comme le fait remarquer Ken, utiliser à l'
return
intérieur d'un lambda renvoie la valeur de ce lambda, mais utiliserreturn
dans un proc renvoie à partir du bloc englobant.Donc, pour la plupart des utilisations rapides, ils sont les mêmes, mais si vous voulez une vérification automatique des arguments stricts (qui peut aussi parfois aider au débogage), ou si vous devez utiliser l'
return
instruction pour renvoyer la valeur de proc, utilisezlambda
.la source
La vraie différence entre procs et lambdas a tout à voir avec les mots-clés de flux de contrôle. Je parle
return
,raise
,break
,redo
,retry
etc. - ces mots de contrôle. Disons que vous avez une instruction return dans un proc. Lorsque vous appelez votre proc, il vous en sortira non seulement, mais reviendra également de la méthode englobante, par exemple:Le final
puts
de la méthode n'a jamais été exécuté, car lorsque nous avons appelé notre proc, celui-return
ci nous a vidés de la méthode. Si, cependant, nous convertissons notre proc en lambda, nous obtenons ce qui suit:Le retour dans le lambda nous vide uniquement du lambda lui-même et la méthode englobante continue de s'exécuter. La façon dont les mots-clés de flux de contrôle sont traités dans les procs et les lambdas est la principale différence entre eux
la source
Il n'y a que deux différences principales.
lambda
vérifie le nombre d'arguments qui lui sont passés,proc
contrairement à a. Cela signifie que alambda
lancera une erreur si vous lui transmettez un nombre incorrect d'arguments, tandis que aproc
ignorera les arguments inattendus et les assigneranil
à ceux qui manquent.lambda
retourne, il repasse le contrôle à la méthode appelante; quand aproc
revient, il le fait immédiatement, sans revenir à la méthode appelante.Pour voir comment cela fonctionne, jetez un œil au code ci-dessous. Notre première méthode appelle a
proc
; le second appelle alambda
.Voyez comment le
proc
dit "Batman va gagner!", C'est parce qu'il revient immédiatement, sans revenir à la méthode batman_ironman_proc.Notre
lambda
, cependant, retourne dans la méthode après avoir été appelée, donc la méthode renvoie le dernier code qu'elle évalue: "Iron Man va gagner!"la source
# Exemples de processus
# Exemples Lambda
Différences entre Procs et Lambdas
Avant d'entrer dans les différences entre procs et lambdas, il est important de mentionner qu'ils sont tous les deux des objets Proc.
Cependant, les lambdas sont une «saveur» différente des procs. Cette légère différence apparaît lors du retour des objets.
1. Lambdas vérifie le nombre d'arguments, alors que procs ne le fait pas
En revanche, les procs ne se soucient pas de savoir s'ils reçoivent un nombre incorrect d'arguments.
2. Lambdas et procs traitent le mot-clé "return" différemment
'return' à l'intérieur d'un lambda déclenche le code juste à l'extérieur du code lambda
'return' à l'intérieur d'un proc déclenche le code en dehors de la méthode où le proc est exécuté
Et pour répondre à votre autre question, laquelle utiliser et quand? Je suivrai @jtbandes comme il l'a mentionné
Publié à l'origine ici
la source
De manière générale, les lambdas sont plus intuitives que les procs car elles sont plus similaires aux méthodes. Ils sont assez stricts sur l'arité et ils sortent simplement lorsque vous appelez le retour. Pour cette raison, de nombreux Rubyistes utilisent les lambdas comme premier choix, à moins qu'ils n'aient besoin des fonctionnalités spécifiques de procs.
Procs: objets de classe
Proc
. Comme les blocs, ils sont évalués dans la portée où ils sont définis. Lambdas: également des objets de classeProc
mais subtilement différents des procs normaux. Ce sont des fermetures comme des blocs et des processus, et en tant que telles, elles sont évaluées dans la portée où elles sont définies.Création de Proc
Création de lambda
b = lambda { |x| x 2
}la source
a = proc { |x| x 2 }
est le même quea = Proc.new { |x| x 2 }
Voici une autre façon de comprendre cela.
Un bloc est un morceau de code attaché à l'appel à un appel d'une méthode sur un objet. Dans l'exemple ci-dessous, self est une instance d'une classe anonyme héritant d'ActionView :: Base dans le framework Rails (qui lui-même comprend de nombreux modules d'assistance). la carte est une méthode que nous appelons nous-mêmes. Nous passons un argument à la méthode puis nous attachons toujours le bloc à la fin de l'appel de la méthode:
Ok, donc nous passons un morceau de code à une méthode. Mais comment utiliser ce bloc? Une option consiste à convertir le morceau de code en un objet. Ruby propose trois façons de convertir un morceau de code en objet
Dans la méthode ci-dessus, le & convertit le bloc passé à la méthode en un objet et stocke cet objet dans le bloc de variables locales. En fait, nous pouvons montrer qu'il a le même comportement que lambda et Proc.new:
C'est important. Lorsque vous passez un bloc à une méthode et que vous le convertissez à l'aide de &, l'objet qu'il crée utilise Proc.new pour effectuer la conversion.
Notez que j'ai évité d'utiliser "proc" comme option. C'est parce que c'est Ruby 1.8, c'est la même chose que lambda et dans Ruby 1.9, c'est la même chose que Proc.new et dans toutes les versions de Ruby, cela devrait être évité.
Alors vous demandez quelle est la différence entre lambda et Proc.new?
Premièrement, en termes de passage de paramètres, lambda se comporte comme un appel de méthode. Cela lèvera une exception si vous passez le mauvais nombre d'arguments. En revanche, Proc.new se comporte comme une affectation parallèle. Tous les arguments inutilisés sont convertis en nil:
Deuxièmement, lambda et Proc.new gèrent le mot clé return différemment. Lorsque vous effectuez un retour à l'intérieur de Proc.new, il retourne en fait à partir de la méthode englobante, c'est-à-dire du contexte environnant. Lorsque vous revenez d'un bloc lambda, il revient simplement du bloc, pas de la méthode englobante. Fondamentalement, il quitte l'appel au bloc et continue l'exécution avec le reste de la méthode englobante.
Alors pourquoi cette différence de comportement? La raison en est qu'avec Proc.new, nous pouvons utiliser des itérateurs dans le contexte des méthodes englobantes et tirer des conclusions logiques. Regardez cet exemple:
Nous nous attendons à ce que lorsque nous invoquons return à l'intérieur de l'itérateur, il revienne de la méthode englobante. N'oubliez pas que les blocs passés aux itérateurs sont convertis en objets à l'aide de Proc.new et c'est pourquoi lorsque nous utilisons return, il quittera la méthode englobante.
Vous pouvez considérer les lambdas comme des méthodes anonymes, elles isolent des blocs de code individuels dans un objet qui peut être traité comme une méthode. En fin de compte, pensez qu'un lambda se comporte comme une méthode anomyous et que Proc.new se comporte comme du code en ligne.
la source
Un article utile sur les guides rubis: blocs, procs et lambdas
la source
la différence entre proc et lambda est que proc est juste une copie de code avec des arguments remplacés à son tour, tandis que lambda est une fonction comme dans d'autres langages. (comportement de retour, vérification des arguments)
la source