В Ruby 1.8 есть тонкие различия между proc / lambda, с одной стороны, и Proc.new, с другой.
Также смотрите подробный пост на Различия в потоке управления между Ruby Procs и Lambdas
вы приняли ответ, в котором только говорится, в чем разница между proc и lambda, а заголовок вашего вопроса - когда использовать эти вещи

Я нашел эта страница, который показывает, в чем разница между Proc.new и lambda. Согласно странице, единственное отличие состоит в том, что лямбда строго определяет количество принимаемых аргументов, тогда как Proc.new преобразует отсутствующие аргументы в nil. Вот пример сеанса IRB, иллюстрирующий разницу:
irb(main):001:0> l = lambda { |x, y| x + y }
=> #<Proc:0x00007fc605ec0748@(irb):1>
irb(main):002:0> p = Proc.new { |x, y| x + y }
=> #<Proc:0x00007fc605ea8698@(irb):2>
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На странице также рекомендуется использовать лямбда, если вы специально не хотите терпимого к ошибкам поведения. Я согласен с этим мнением. Использование лямбды кажется немного более кратким, и с такой незначительной разницей это кажется лучшим выбором в средней ситуации.
Что касается Ruby 1.9, извините, я еще не изучал 1.9, но я не думаю, что они все это изменит (хотя не верьте мне на слово, похоже, вы слышали о некоторых изменениях, поэтому Я, наверное, ошибаюсь в этом).
procs также возвращаются иначе, чем лямбды.
"" "Proc.new преобразует отсутствующие аргументы в ноль" "" Proc.new также игнорирует дополнительные аргументы (конечно, лямбда сообщает об ошибке).
Еще одно важное, но тонкое различие между процедурами, созданными с помощью lambda, и процедурами, созданными с помощью Proc.new, заключается в том, как они обрабатывают оператор return:
lambda, инструкция return возвращается только из самой процедуры.Proc.new, инструкция return немного более удивительна: она возвращает управление не только из процесса, но также из метода, включающего proc!Вот созданный lambda процесс return в действии. Он ведет себя так, как вы, вероятно, ожидаете:
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"
Теперь вот созданный Proc.new протокол return, который делает то же самое. Вы вот-вот увидите один из тех случаев, когда Руби нарушает хваленый принцип наименьшего сюрприза:
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"
Благодаря этому удивительному поведению (а также меньшему количеству набора текста) я предпочитаю использовать lambda вместо Proc.new при создании процедур.
Еще есть метод proc. Это просто сокращение от Proc.new?
@mattdipasquale В моих тестах proc действует как lambda, а не как Proc.new в отношении операторов возврата. Это означает, что рубиновый документ неточен.
@mattdipasquale Извини, я был прав только наполовину. proc действует как lambda в 1.8, но действует как Proc.new в 1.9. См. Ответ Питера Вагенета.
Почему такое «удивительное» поведение? lambda - анонимный метод. Поскольку это метод, он возвращает значение, а вызвавший его метод может делать с ним все, что захочет, в том числе игнорировать его и возвращать другое значение. Proc похож на вставку фрагмента кода. Это не действует как метод. Поэтому, когда возврат происходит внутри Proc, это всего лишь часть кода метода, который его вызвал.
Как указал Арколай, «процессы в Ruby - это фрагменты кода, а не методы». От robertsosinski.com/2008/12/21/…. Так что возвращение происходит в самом whowouldwin2.
Я считаю, что основное различие заключается также в том, что Proc не вызывает ошибок, когда вы указываете отсутствующие / дополнительные аргументы, тогда как lambdas выдает ошибку wrong number of arguments.
Ответ на этот счет неясен, и приведенный выше комментарий Аркойла просто неверен: return в Proc возвращается из контекста, который создал процесс, не контекст, который вызвал процесс. Эта ошибка везде!
Разница в поведении с return - это, IMHO, самая важная разница между 2. Я также предпочитаю лямбда, потому что она меньше печатает, чем Proc.new :-)
Для обновления: теперь процессы можно создавать с помощью proc {}. Я не уверен, когда это вступило в силу, но это (немного) проще, чем набирать Proc.new.
Замыкания в Ruby - хороший обзор того, как блоки, лямбда-выражения и процессы работают в Ruby с Ruby.
Я перестал читать это после того, как прочитал «функция не может принимать несколько блоков - нарушая принцип, согласно которому замыкания могут свободно передаваться как значения». Блоки - это не закрытие. Процедуры есть, и функция может принимать несколько процедур.
Чтобы подробнее рассказать об ответе Accordion Guy:
Обратите внимание, что Proc.new создает процесс, передавая блок. Я считаю, что lambda {...} анализируется как своего рода литерал, а не как вызов метода, который передает блок. return изнутри блока, прикрепленного к вызову метода, будет возвращаться из метода, а не из блока, и случай Proc.new является примером этого в действии.
(Это 1.8. Я не знаю, как это переводится в 1.9.)
Proc старше, но семантика return мне очень противоречит интуиции (по крайней мере, когда я изучал язык), потому что:
Lambda функционально безопаснее, и о ней легче рассуждать - я всегда использую ее вместо proc.
Я не могу много сказать о тонких различиях. Тем не менее, я могу указать, что Ruby 1.9 теперь допускает необязательные параметры для лямбда-выражений и блоков.
Вот новый синтаксис stabby lambdas в версии 1.9:
stabby = ->(msg='inside the stabby lambda') { puts msg }
В Ruby 1.8 такого синтаксиса не было. Также традиционный способ объявления блоков / лямбда-выражений не поддерживает необязательные аргументы:
# 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 поддерживает необязательные аргументы даже со старым синтаксисом:
l = lambda { |msg = 'inside the regular lambda'| puts msg }
#=> #<Proc:0x0e5dbc@(irb):1 (lambda)>
l.call
#=> inside the regular lambda
l.call('jeez')
#=> jeez
Если вы хотите собрать Ruby1.9 для Leopard или Linux, попробуйте Эта статья (бессовестная самореклама).
Необязательные параметры в лямбдах были очень необходимы, я рад, что они добавили их в 1.9. Я предполагаю, что блоки также могут иметь необязательные параметры (в 1.9)?
вы не демонстрируете параметры по умолчанию в блоках, только лямбды
Хороший способ увидеть, что лямбды выполняются в своей собственной области (как если бы это был вызов метода), в то время как Procs можно рассматривать как выполняемые в строке с вызывающим методом, по крайней мере, это хороший способ решить, какой из них использовать. в каждом случае.
Я не заметил никаких комментариев к третьему методу в квестоне, "proc", который устарел, но обрабатывается по-другому в 1.8 и 1.9.
Вот довольно подробный пример, который позволяет легко увидеть различия между тремя похожими вызовами:
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
Мац заявил, что планировал отказаться от него, потому что это сбивает с толку, когда proc и Proc.new возвращают разные результаты. Однако в 1.9 они ведут себя так же (proc - это псевдоним для Proc.new). eigenclass.org/hiki/Changes+in+Ruby+1.9#l47
@banister: proc вернул лямбду в версии 1.8; теперь исправлено возвращать процесс в 1.9 - однако это критическое изменение; поэтому больше не рекомендуется использовать
Я думаю, что кирка где-то в сноске говорит, что прок эффективно лишен или что-то в этом роде. У меня нет точного номера страницы.
Чтобы дать дополнительные пояснения:
Джои говорит, что обратное поведение Proc.new вызывает удивление. Однако, если учесть, что Proc.new ведет себя как блок, это неудивительно, поскольку именно так ведут себя блоки. с другой стороны, ламбы больше похожи на методы.
Это фактически объясняет, почему Procs гибки, когда дело доходит до арности (количества аргументов), а лямбды - нет. Блоки не требуют предоставления всех своих аргументов, но методы требуют (если не указано значение по умолчанию). Хотя предоставление лямбда-аргумента по умолчанию не является опцией в Ruby 1.8, теперь оно поддерживается в Ruby 1.9 с альтернативным синтаксисом лямбда (как отмечает webmat):
concat = ->(a, b=2){ "#{a}#{b}" }
concat.call(4,5) # => "45"
concat.call(1) # => "12"
И Мишель де Маре (OP) неверен в том, что Procs и лямбда ведут себя одинаково с arity в Ruby 1.9. Я подтвердил, что они по-прежнему поддерживают поведение с версии 1.8, как указано выше.
Операторы break на самом деле не имеют особого смысла ни в Procs, ни в лямбдах. В Procs перерыв вернет вас из Proc.new, который уже был завершен. И нет никакого смысла отказываться от лямбды, поскольку это, по сути, метод, и вы никогда не откажетесь от верхнего уровня метода.
next, redo и raise ведут себя одинаково как в Procs, так и в лямбдах. В то время как retry не допускается ни в одном из них и вызовет исключение.
И, наконец, никогда не следует использовать метод proc, поскольку он непоследователен и имеет неожиданное поведение. В Ruby 1.8 он фактически возвращает лямбду! В Ruby 1.9 это было исправлено, и он возвращает Proc. Если вы хотите создать Proc, придерживайтесь Proc.new.
Для получения дополнительной информации я настоятельно рекомендую O'Reilly's Язык программирования Ruby, который является моим источником большей части этой информации.
"" "Однако, если учесть, что Proc.new ведет себя как блок, это не удивительно, поскольку именно так ведут себя блоки." ""
Начиная с Ruby 2.5, break из Procs поднимает LocalJumpError, тогда как break из лямбда-выражений ведет себя так же, как return (т.е., return nil).
Краткий ответ: важно то, что делает return: лямбда возвращается из себя, а процедура возвращает из себя И функции, которая ее вызвала.
Менее ясно, почему вы хотите использовать каждый из них. лямбда - это то, что мы ожидаем от вещей в смысле функционального программирования. По сути, это анонимный метод с автоматически привязанной текущей областью видимости. Из двух, вам, вероятно, следует использовать лямбда.
Proc, с другой стороны, действительно полезен для реализации самого языка. Например, с ними можно реализовать операторы if или циклы for. Любой возврат, найденный в процедуре, будет возвращен из метода, который его вызвал, а не только из оператора «if». Так работают языки, как работают операторы «если», поэтому я предполагаю, что Ruby использует это под прикрытием, и они просто раскрыли его, потому что это казалось мощным.
Вам это действительно понадобится, только если вы создаете новые языковые конструкции, такие как циклы, конструкции if-else и т. д.
«лямбда возвращается из себя, а процедура возвращается из себя, И функция, которая ее вызвала» - это явная ошибка и очень распространенное недоразумение. Процедура является закрытием и возвращается из метода, который ее создал. Смотрите мой полный ответ в другом месте на странице.
лямбда работает должным образом, как и на других языках.
Проводной Proc.new удивляет и сбивает с толку.
Оператор return в процессе, созданный Proc.new, вернет управление не только самому себе, но и также из метода, включающего его.
def some_method
myproc = Proc.new {return "End."}
myproc.call
# Any code below will not get executed!
# ...
end
Вы можете утверждать, что Proc.new вставляет код во включающий метод, как и блок.
Но Proc.new создает объект, а блок - это часть объект.
И есть еще одно различие между лямбдой и Proc.new, которое заключается в обработке (неправильных) аргументов.
lambda жалуется на это, в то время как Proc.new игнорирует лишние аргументы или считает отсутствие аргументов нулевым.
irb(main):021:0> l = -> (x) { x.to_s }
=> #<Proc:0x8b63750@(irb):21 (lambda)>
irb(main):022:0> p = Proc.new { |x| x.to_s}
=> #<Proc:0x8b59494@(irb):22>
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 `<main>'
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 `<main>'
irb(main):050:0> p.call 1, 2
=> "1"
Кстати, proc в Ruby 1.8 создает лямбду, а в Ruby 1.9+ ведет себя как Proc.new, что действительно сбивает с толку.
Я немного опоздал с этим, но есть одна замечательная, но малоизвестная вещь о Proc.new, которая вообще не упоминается в комментариях. Согласно документация:
Proc::newmay be called without a block only within a method with an attached block, in which case that block is converted to theProcobject.
Тем не менее, Proc.new позволяет связывать методы получения:
def m1
yield 'Finally!' if block_given?
end
def m2
m1 &Proc.new
end
m2 { |e| puts e }
#⇒ Finally!
Интересно, что он делает то же самое, что и объявление аргумента &block в def, но без необходимости делать это в списке def arg.
Стоит подчеркнуть, что return в процессе возвращается из метода лексического включения, то есть метод, в котором был создан процесс, нет метода, который вызвал процесс. Это следствие закрывающего свойства procs. Итак, следующий код ничего не выводит:
def foo
proc = Proc.new{return}
foobar(proc)
puts 'foo'
end
def foobar(proc)
proc.call
puts 'foobar'
end
foo
Хотя процедура выполняется в foobar, она была создана в foo, поэтому return выходит из foo, а не только из foobar. Как писал выше Чарльз Колдуэлл, в нем есть чувство GOTO. На мой взгляд, return подходит для блока, который выполняется в его лексическом контексте, но гораздо менее интуитивно понятен при использовании в процессе, который выполняется в другом контексте.
См. Также: книгу Матца и Фланагана по языку программирования Ruby, в которой эта тема исчерпывающе раскрыта. proc ведет себя как семантика выхода блока, тогда как лямбда ведет себя как семантика вызова метода. Также return, break, et. все ведут себя по-разному в процедурах и лямбдах