Що таке Proc і Lambda в Ruby?

Обкладинка допису: Що таке Proc і Lambda в Ruby?
У Ruby Proc - це об’єкт, який зберігає шматок коду (блок) і дозволяє виконувати його пізніше. Це як "збережений блок" або "функція в коробці".

Приклад 1: створюємо Proc

say_hello = Proc.new { puts "Hello!" }
say_hello.call
# => "Hello!"
Ми створили об’єкт Proc, який зберігає код { puts "Hello!" }. Потім викликали його через .call.

Приклад 2: передаємо Proc у метод

def run_twice(proc)
  proc.call
  proc.call
end

run_twice(Proc.new { puts "Hi!" })
# => "Hi!"
# => "Hi!"
Ми передали блок коду як об’єкт і викликали його кілька разів. Це дуже зручно, коли потрібно повторно використовувати логіку.

Proc - чому така назва?

Легше запам'ятовувати назви методів, коли знаєш що воно означає. Назва Proc у Ruby - це скорочення від "Procedure" (процедура). У мовах програмування, ще з часів Lisp і Scheme, термін procedure означав "шматок коду, який можна виконати пізніше" - тобто функцію, яку можна передати як аргумент або викликати.
Коли Мацумото (Matz), творець Ruby, проєктував мову, він хотів, щоб Ruby мав простий і гнучкий спосіб роботи з блоками коду. Він узяв ідею процедур із Lisp/Scheme і зробив їх об’єктами - так з’явився клас Proc (procedure object).

Що таке Lambda?

Lambda - це теж Proc, але з деякими відмінностями. Її можна створити кількома способами:
-> { }
say_hi = -> { puts "Hi!" }
say_hi.call
# => "Hi!"
та lambda {}
say_hello = lambda { puts "Hello!" }
Ну а щоб довести, що лямбда це прок:
say_hi.class
=> Proc

Основна різниця між Proc і Lambda

1. Lambda перевіряє кількість аргументів, а Proc - ні.
p1 = Proc.new { |a, b| puts a, b }
l1 = ->(a, b) { puts a, b }

p1.call(1)
# => 1
# => nil   (другий аргумент просто nil)

l1.call(1)
# => ArgumentError: wrong number of arguments
2. return у Proc виходить із всього методу, а не лише з Proc. У Lambda return завершує тільки саму лямбду.
І розглянемо приклади
def test_proc
  p = Proc.new { return "From Proc" }
  p.call
  "After Proc"  # цей рядок не виконається
end

puts test_proc
# => "From Proc"
Коли Proc викликає return, він одразу виходить із методу, у якому створений Proc, а не лише з блоку.
return у Lambda завершує тільки саму лямбду
def test_lambda
  l = -> { return "From Lambda" }
  result = l.call
  "After Lambda: #{result}"  # цей рядок виконається
end

puts test_lambda
# => "After Lambda: From Lambda"
Лямбда поводиться як звичайний метод: return завершує лише саму лямбду, а метод продовжує виконання далі.

& і to_proc

Коли ви передаєте у Ruby об’єкт із амперсандом &, Ruby робить спробу викликати на ньому .to_proc і використовує отриманий Proc як блок.
def run(&block)
  block.call
end

run { puts "Works!" }
# => "Works!"
Тут Ruby автоматично викликав .to_proc для нашого блоку { ... } і передав його в змінну block.

Цей допис поки що не має жодних доповнень від автора/ки.

Як працюють масиви в Ruby: практичні приклади each, map, select, inject, reduce, filter_map
28 жовт., 10:38

Як працюють масиви в Ruby: практичні приклади each, map, select, inject, reduce, filter_map

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Як працює self, protected і private (Ruby)
28 жовт., 13:52

Як працює self, protected і private (Ruby)

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Цілочисельне ділення у Ruby: чому 6 / 4 дорівнює 1
28 жовт., 14:10

Цілочисельне ділення у Ruby: чому 6 / 4 дорівнює 1

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
28 жовт., 14:42

Як працює &:to_s у Ruby і що таке Symbol#to_proc

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Що відбувається, якщо викликати [1, 2, 3].map(&Person)
29 жовт., 17:54

Що відбувається, якщо викликати [1, 2, 3].map(&Person)

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Singleton class (eigenclass) у Ruby: що це і навіщо потрібно
29 жовт., 18:29

Singleton class (eigenclass) у Ruby: що це і навіщо потрібно

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
==, equal?, eql?, === у Ruby: що перевіряють і коли використовувати
29 жовт., 20:47

==, equal?, eql?, === у Ruby: що перевіряють і коли використовувати

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Include, Extend, Prepend у Ruby: як вони працюють і в чому різниця
29 жовт., 21:20

Include, Extend, Prepend у Ruby: як вони працюють і в чому різниця

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
module_function у Ruby: коли методи модуля доступні як модульні та як функції
29 жовт., 21:53

module_function у Ruby: коли методи модуля доступні як модульні та як функції

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Що таке memoization в Ruby?
30 жовт., 10:17

Що таке memoization в Ruby?

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska