Подтвердить что ты не робот

Где и когда использовать Лямбду?

Я пытаюсь понять, почему нам действительно нужны lambda или proc в 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.

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

4b9b3361

Ответ 1

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

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 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 fed, которая затем должна быть дана бесполезным именем, когда так же ясно, как писать операцию в строке. Это правда, что там нигде вы не должны использовать лямбда, но есть много мест, которые я бы скорее использовал лямбдой.

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

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


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

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

Ответ 2

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

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

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

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

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

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

Ответ 3

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

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

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

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

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]

Ответ 4

Это сводится к стилю. Lambdas - декларативный стиль, методы - императивный стиль. Рассмотрим это:

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

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

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

Также lambdas, естественно, поддаются рекурсии и перечислению.

Ответ 5

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

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 }

поэтому он более гибкий.

Ответ 6

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

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

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

Ответ 7

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

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

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

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

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

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