30 votes

Est Ruby même bloc de code C#, s'expression lambda?

Ce sont ces deux essentiellement la même chose? Ils ont l'air très similaire à moi.

N'expression lambda emprunter son idée de Ruby?

45voto

Matt Briggs Points 20291

Ruby a en fait 4 constructions qui sont tous très similaires

Le Bloc

L'idée derrière des blocs est en quelque sorte une façon de mettre en œuvre réellement le poids léger de la stratégie de modèles. Un bloc de définir une coroutine sur la fonction, la fonction peut déléguer le contrôle avec le mot clé yield. Nous utilisons des blocs pour à peu près tout le rubis, y compris à peu près toutes les constructions de bouclage ou partout où vous utilisez using en c#. En dehors de tout le bloc est dans l'étendue du bloc, cependant l'inverse n'est pas vrai, à l'exception de retour à l'intérieur du bloc sera de retour l'extérieur de la portée. Ils ressemblent à ceci

def foo
  yield 'called foo'
end

#usage
foo {|msg| puts msg} #idiomatic for one liners

foo do |msg| #idiomatic for multiline blocks
  puts msg
end

Proc

Un proc c'est en fait prendre un bloc et de le transmettre autour de lui comme un paramètre. Il est extrêmement intéressant d'utiliser de ceci est que vous pouvez passer un proc comme un remplacement pour un bloc d'une autre méthode. Ruby a un caractère spécial pour le proc contrainte qui est &, et une règle spéciale que si le dernier param dans une signature de méthode commence avec un &, ce sera un proc représentation du bloc pour l'appel de méthode. Enfin, il y a un builtin méthode appelée block_given?, ce qui renvoie true si la méthode actuelle a un bloc défini. Il ressemble à ceci

def foo(&block)
  return block
end

b = foo {puts 'hi'}
b.call # hi

Pour aller un peu plus loin avec cela, il y a vraiment une astuce que rails ajouté Symbole (et obtenu fusionné dans le cœur de ruby en 1.9). Fondamentalement, c'est la coercition ne sa magie en appelant to_proc sur ce qu'il est à côté. Si les rails gars ajouté un Symbole#to_proc qui allait s'appeler lui-même sur tout ce qui est passé. Qui vous permet d'écrire quelques très laconique code pour toute agrégation de style de la fonction, qui est juste à l'appel d'une méthode sur chaque objet dans une liste

class Foo
  def bar
    'this is from bar'
  end
end

list = [Foo.new, Foo.new, Foo.new]

list.map {|foo| foo.bar} # returns ['this is from bar', 'this is from bar', 'this is from bar']
list.map &:bar # returns _exactly_ the same thing

Des choses plus avancées, mais l'omi qui illustre vraiment le genre de magie que vous pouvez faire avec les procs

Les Lambdas

Le but d'un lambda est à peu près la même dans le rubis qu'il est en c#, un moyen de créer une fonction en ligne de transmettre autour de, ou les utiliser en interne. Comme les blocs et les procs, les lambdas sont des fermetures, mais contrairement aux deux premiers, il applique arité, et de retour de lambda sort de la lambda, pas le contenant portée. Vous en créer un en passant un bloc pour le lambda de la méthode, ou d' -> en ruby 1.9

l = lambda {|msg| puts msg} #ruby 1.8
l = -> {|msg| puts msg} #ruby 1.9

l.call('foo') # => foo

Méthodes

Seulement grave, ruby geeks vraiment comprendre celui-ci: a) une méthode est Un moyen de transformer une fonction existante dans quelque chose que vous pouvez mettre dans une variable. Vous obtenez une méthode par l'appel de la method de la fonction, et en le passant dans un symbole comme le nom de la méthode. Vous pouvez lier une méthode, ou vous pouvez forcer un proc si vous voulez montrer. Une façon de ré-écrire la méthode précédente serait

l = lambda &method(:puts)
l.call('foo')

Ce qui se passe ici, c'est que vous êtes la création d'une méthode pour les options de vente, le fait de contraindre dans un proc, en passant, que comme un remplacement pour un bloc pour le lambda méthode, qui à son tour vous renvoie le lambda


N'hésitez pas à demander au sujet de tout ce qui n'est pas clair (écrit ce vraiment la fin sur un soir de semaine sans un de la cisr, j'espère qu'il n'est pas pur charabia)

EDIT: Pour répondre à des questions dans les commentaires

liste.carte &:bar puis-je utiliser cette syntaxe avec un bloc de code qui prend plus d' un argument? Dire que j'ai hash = { 0 => "bonjour", 1 => "monde" }, et je veux sélectionnez les éléments que a 0 comme clé. Peut-être pas un bon exemple. – Bryan Shen

Vas sorte de profonde ici, mais pour vraiment comprendre comment cela fonctionne, vous devez comprendre comment ruby appels de méthode de travail.

Fondamentalement, ruby n'est pas un concept de l'invocation d'une méthode, ce qui se passe est que les objets faire passer des messages les uns aux autres. L' obj.method arg de la syntaxe que vous utilisez est vraiment juste un peu de sucre autour de la plus explicite de la forme, qui est - obj.send :method, arg, et est fonctionnellement équivalente à la première syntaxe. C'est un concept fondamental dans la langue, et c'est pourquoi les choses comme method_missing et respond_to? sens, dans le premier cas, vous êtes juste de la manipulation de messages non reconnus, le deuxième vous de vérifier pour voir si elle est à l'écoute de ce message.

L'autre chose à savoir, c'est le plutôt ésotérique "splat" de l'opérateur, *. Selon l'endroit où il est utilisé, il ne fait que des choses très différentes.

def foo(bar, *baz)

Dans un appel de méthode, si c'est le dernier paramètre, splat va faire ce paramètre glob jusqu'tous les autres paramètres passés à la fonction (un peu comme params en C#)

obj.foo(bar, *[biz, baz])

Quand, dans un appel de méthode (ou autre chose qui prend de listes d'arguments), il va se transformer un tableau en une simple liste d'arguments. L'extrait de code ci-dessous est équivalent à l'extrait ci-dessus.

obj.foo(bar, biz, baz)

Maintenant, avec send et * dans l'esprit, Symbol#to_proc est essentiellement mis en œuvre comme ceci

class Symbol
  def to_proc
    Proc.new { |obj, *args| obj.send(self, *args) }
  end
end

Donc, &:sym va faire un nouveau proc, qui appelle .send :sym sur le premier argument passé à elle. Si d'autres arguments sont passés, ils sont globbed dans un tableau appelé args, puis splatted dans l' send appel de la méthode.

Je remarque que & est utilisé dans trois lieux: def foo(&block), liste.carte &:bar, et l = lambda et méthode(:met). Partagent-ils le même sens? – Bryan Shen

Oui, ils le font. Un & appellera to_proc sur ce que jamais, il est à côté. Dans le cas de la définition de la méthode qu'il a une signification particulière lorsque le dernier paramètre, où vous êtes en tirant dans la co-routine défini comme un bloc, et les transformant en un proc. Les définitions de méthode sont en fait l'une des pièces les plus complexes de la langue, il y a une énorme quantité de trucs et astuces et des significations particulières qui peuvent être dans les paramètres, et le placement des paramètres.

b = {0 => "df", 1 => "kl"} p b.sélectionnez {|clé, valeur| clé.zéro? } J'ai essayé de transformer ce p.b.sélectionnez &:zéro?, mais il a échoué. Je suppose que c'est parce que le nombre de paramètres pour le code le bloc est deux, mais &:de zéro? ne peut prendre un param. Est il possible que je peux faire cela? – Bryan Shen

Cette question devrait être abordée plus tôt, malheureusement, vous ne pouvez pas le faire avec ce truc.

"Une méthode est un moyen de transformer un existant la fonction dans quelque chose que vous pouvez mettre en une variable." pourquoi est-l = méthode(:met) pas suffisant? Ce n'lambda & dans ce contexte? – Bryan Shen

Cet exemple a été exceptionnellement tiré par les cheveux, je voulais juste montrer le code équivalent à l'exemple d'avant, où j'ai été en passant un proc à l' lambda méthode. Je vais prendre quelques temps plus tard, et ré-écrire un peu, mais vous avez raison, method(:puts) est totalement suffisant. Ce que je voulais montrer, c'est que vous pouvez utiliser &method(:puts) n'importe où que ce serait prendre un bloc. Un meilleur exemple serait celui-ci

['hello', 'world'].each &method(:puts) # => hello\nworld

l = -> {|msg| met msg} #ruby 1.9: cela ne fonctionne pas pour moi. Après Je vérifié Jörg réponse, je pense que c' devrait être l = -> (msg) {puts msg}. Ou peut-être que je suis en utilisant une version incorrecte de Ruby? Le mien est ruby 1.9.1p738 – Bryan Shen

Comme je l'ai dit dans le post, je n'ai pas eu de rir disponible quand j'ai écrit la réponse, et vous avez raison, j'ai raté son coup qu' (passer la grande majorité de mon temps dans 1.8.7, donc je ne suis pas habitué à la nouvelle syntaxe encore)

Il n'y a pas d'espace entre l'aimant bits et parens. Essayez l = ->(msg) {puts msg}. Il y a effectivement beaucoup de résistance à cette syntaxe, car il est tellement différent de tout le reste dans la langue.

8voto

Joel Spolsky Points 22686

Pas exactement. Mais ils sont très similaires. La différence la plus évidente est qu'en C# d'une expression lambda peut aller partout où vous pourriez avoir une valeur qui se trouve être une fonction; en Ruby, vous n'avez qu'un bloc de code par appel de méthode.

Ils ont emprunté tous les deux l'idée de Lisp (un langage de programmation datant de la fin des années 1950) qui, à son tour emprunté le lambda concept de l'Église du Lambda Calcul, inventé dans les années 1930.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X