Где и когда использовать лямбду? - PullRequest
28 голосов
/ 04 декабря 2010

Я пытаюсь понять, зачем нам действительно нужна лямбда или процедура в ruby ​​(или любом другом языке в этом отношении)?

#method
def add a,b
  c = a+b
end

#using proc
def add_proc a,b
  f = Proc.new {|x,y| x + y }
  f.call a,b
end

#using lambda function
def add_lambda a,b
  f = lambda {|x,y| x + y}
  f.call a,b
end

puts add 1,1
puts add_proc 1,2
puts add_lambda 1,3

Я могу сделать простое дополнение, используя: 1. нормальную функцию def, 2. используя proc и 3. используя lambda.

Но зачем и где использовать лямбду в реальном мире?Любые примеры, где нельзя использовать функции и использовать лямбду.

Ответы [ 7 ]

20 голосов
/ 04 декабря 2010

Это правда, вам не нужны анонимные функции (или лямбды, или как вы хотите их вызывать).Но есть много вещей, которые вам не нужны .Вам не нужны классы - просто передайте все переменные экземпляра обычным функциям.Тогда

class Foo
  attr_accessor :bar, :baz
  def frob(x)
    bar = baz*x
  end
end

станет

def new_Foo(bar,baz)
  [bar,baz]
end

def bar(foo)
  foo[0]
end
# Other attribute accessors stripped for brevity's sake

def frob(foo,x)
  foo[0] = foo[1]*x
end

Аналогично, вам не нужно никаких циклов, кроме loop...end с if и break.Я мог бы продолжать и продолжать. 1 Но вы хотите, чтобы программировал с классами на Ruby.Вы хотите, чтобы могли использовать while петли или, может быть, даже array.each { |x| ... }, и вы хотите иметь возможность использовать unless вместо if not.

Так же, какЭти функции, анонимные функции помогут вам выразить вещи элегантно, лаконично и осмысленно.Возможность писать some_function(lambda { |x,y| x + f(y) }) гораздо приятнее, чем писать

def temp(x,y)
  x + f(y)
end
some_function temp

Гораздо громче приходится прерывать поток кода, чтобы написать функцию с подпиткой def, которая затем должна бытьдано бесполезное имя, когда так же ясно написать операцию в строке.Это правда, что нигде вы не должны использовать лямбду, но есть много мест, в которых я бы предпочел использовал бы лямбду.

Ruby решает большую частьЛямбда-случаи с блоками: все функции, такие как each, map и open, которые могут принимать блок в качестве аргумента, в основном принимают анонимную функцию в специальном корпусе.array.map { |x| f(x) + g(x) } - это то же самое, что и array.map(&lambda { |x| f(x) + g(x) }) (где & делает лямбду «особенной» точно так же, как голый блок).Опять же, вы могли бы каждый раз записывать отдельную функцию def feed - но зачем вам хотеть to?

Языки, отличные от Ruby, которые поддерживают этот стильпрограммирование не имеет блоков, но часто поддерживает более легкий лямбда-синтаксис, такой как \x -> f x + g x на Haskell или x => f(x) + g(x); 2 на C #.Каждый раз, когда у меня есть функция, которая должна принимать абстрактное поведение, например, map, или each, или on_clicked, я буду благодарен за возможность передавать лямбду вместо именованной функциипотому что это намного проще .В конце концов, вы перестаете думать о них как о чем-то особенном - они так же интересны, как буквальный синтаксис для массивов вместо empty().append(1).append(2).append(3).Просто еще одна полезная часть языка.


1: В вырожденном случае вам действительно нужно только восемь инструкций : +-<>[].,.<> переместить воображаемый «указатель» вдоль массива;+- увеличить и уменьшить число в текущей ячейке;[] выполнить цикл пока ненулевой;и ., делать ввод и вывод.На самом деле вам нужна всего лишь одна инструкция , например subleq a b c (вычтите a из b и перейдите к c, если результат меньше или равен нулю).

2: На самом деле я никогда не использовал C #, поэтому, если этот синтаксис неправильный, не стесняйтесь его исправлять.

6 голосов
/ 07 декабря 2013

Все сводится к стилю.Лямбды - это декларативный стиль, методы - это императивный стиль.Учтите это:

Лямбда, блоки, процы - все это разные типы замыкания.Теперь вопрос в том, когда и зачем использовать анонимное закрытие.Я могу ответить на это - по крайней мере, в ruby!

Замыкания содержат лексический контекст того, откуда они были вызваны.Если вы вызываете метод изнутри метода, вы не получите контекст, где был вызван метод.Это связано с тем, как цепочка объектов хранится в AST.

С другой стороны, замыкание (лямбда) может быть передано с лексическим контекстом через метод, позволяющий выполнять ленивую оценку.1008 * Также лямбды естественным образом поддаются рекурсии и перечислению.

6 голосов
/ 04 декабря 2010

Блоки - более или менее одно и то же

Ну, в Ruby обычно не используют лямбда или процесс, потому что блоки - это одно и то же и гораздо удобнее.

Использование бесконечно, но мы можем перечислить некоторые типичные случаи.Обычно думают о функциях как о блоках нижнего уровня, выполняющих часть обработки, возможно, написанную в общем и превращенную в библиотеку.

Но довольно часто хочется автоматизировать оболочку и предоставить собственную библиотеку.Представьте себе функцию, которая устанавливает соединение HTTP или HTTPS или прямую TCP, передает ввод-вывод своему клиенту, а затем закрывает соединение.Или, может быть, просто делает то же самое с простым старым файлом.

Так что в Ruby мы поместили бы функцию в библиотеку, и она бы взяла блок для пользователя ... клиента ... "вызывающего" длянаписать свою логику приложения.

На другом языке это должно быть сделано с помощью класса, реализующего интерфейс, или указателя на функцию.В Ruby есть блоки, но все они являются примерами шаблона дизайна в стиле лямбды.

5 голосов
/ 06 декабря 2010

1) Это просто удобство. Вам не нужно называть определенные блоки

special_sort(array, :compare_proc => lambda { |left, right| left.special_param <=> right.special_param }

(представьте, если бы вы назвали все эти блоки)

2) #lambda обычно используется для создания замыканий:

def generate_multiple_proc(cofactor)
  lambda { |element| element * cofactor }
end

[1, 2, 3, 4].map(&generate_multiple_proc(2)) # => [2, 3, 5, 8]

[1, 2, 3, 4].map(&generate_multiple_proc(3)) # => [3, 6, 9, 12]
2 голосов
/ 04 декабря 2010

Они используются как функции высшего порядка. В основном, для случаев, когда вы передаете одну функцию другой, чтобы получающая функция могла вызывать переданную функцию в соответствии со своей собственной логикой.

Это часто встречается в Ruby для итерации, например, some_list.each {| item | ...} сделать что-то для each item из some_list. Хотя обратите внимание, что мы не используем ключевое слово lambda; как уже отмечалось, блок - это одно и то же.

В Python (так как у нас есть тег language-agnostic по этому вопросу), вы не можете написать что-либо, похожее на блок Ruby, поэтому ключевое слово lambda появляется чаще. Тем не менее, вы можете получить аналогичный эффект «быстрого вызова» из списков и выражений генератора.

2 голосов
/ 04 декабря 2010

В случае ООП вы должны создавать функцию в классе, только если в классе должна быть такая операция в соответствии с моделированием вашего домена.

Если вам нужна быстрая функция, которая может быть написана встроенной, например, для сравнения и т. Д., Используйте лямбду

Также проверьте эти SO сообщения -

Когда использовать лямбду, когда использовать Proc.new?

C # Лямбда-выражения: зачем их использовать?

Когда использовать лямбду в Ruby on Rails?

2 голосов
/ 04 декабря 2010

Я нашел это полезным для понимания различий:

http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/

Но, в общем, иногда дело в том, что вы пишете метод, но вы не знаете, что вы хотите сделать в определенный момент этого метода, поэтому вы позволяете вызывающему решить.

например:.

def iterate_over_two_arrays(arr1, arr2, the_proc)
  arr1.each do |x|
    arr2.each do |y|
      # ok I'm iterating over two arrays, but I could do lots of useful things now
      #  so I'll leave it up to the caller to decide by passing in a proc
      the_proc.call(x,y)
    end
  end
end

Тогда вместо написания iterate_over_two_arrays_and_print_sum метода и iterate_over_two_arrays_and_print_product метода вы просто вызываете:

iterate_over_two_arrays([1,2,3], [4,5,6], Proc.new {|x,y| puts x + y }

или

iterate_over_two_arrays([1,2,3], [4,5,6], Proc.new {|x,y| puts x * y }

так что он более гибкий.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...