루비 block, lambda, proc
block
객체가 아니다. 그냥 코드 블럭, 그런데 이제 argument를 넘겨 받고 결과를 리턴할 수 있는 익명 함수 역할 하는.
def f
result = yield 3
p result
end
f { |x| x * 7 }
#=> 21
syntax
do / end 혹은 { } curly bracket
yield
메소드 안에서 block을 호출하는데 쓰인다.
한 메소드 안에서 yield를 여러번 호출 할 수도 있고, yield와 함께 block에 n개의 인자를 넘겨줄 수도 있다.
그리고 block의 리턴값이 yield 문 evaluated value가 된다.
def one_two_three
yield 1
yield 2
yield 3
end
one_two_three { |number| puts number * 10 }
# 10, 20, 30
explicit block vs implicit block
🧸 implicit => 위의 예시 대로 하는 것 (yield로 호출)
🧸 explicit => 메소드 내부에서 명시적으로 block에 이름을 붙여줌. (proc 객체로 변환한 뒤 call 메소드로 호출)
def explicit_block(n, &block)
block.call # same as yield
end
explicit_block(3) { puts "Explicit block called" }
# n=> 3
# block => Proc.new { puts "Explicit block called" }
block은 객체가 아니니까 명시적으로 parameter로 받으려면 & 붙여서 proc 객체로 변환한 뒤 받아야 하고
lambda, proc객체는 일급 객체라서 아무것도 안붙인 그냥 파라미터로 넘겨 받음
block_given?
받은 block 없이 메소드 내에서 yield를 호출하면 error 발생하니 block_given? 으로 확인한 다음 yield 할 것.
===
Proc 클래스
Proc 클래스만 존재함. lambda는 스페셜한 Proc 인스턴스. proc 인스턴스에는 lambda? 메소드가 존재함.
* 밑에서 부터는 lambda가 아닌 proc 인스턴스를 proc, lambda인 proc 인스턴스를 lambda라고 부르겠음.
block은 객체가 아님.
proc, lambda는 객체이기 때문에 변수에 저장하고 함수 결과 값으로 리턴할 수도 있다. 함수를 일급객체로 만들어 줌.
call 메소드로 호출.
lambda
syntax
times_two = ->(x) { x * 2 }
times_two = lambda {|x| x * 2}
proc
syntax
my_proc = Proc.new { |x| puts x }
lambda vs proc
1
lambda는 인자 개수 정확히 넘어왔는지 체크하고 error raise하는데, non-lambda인 proc인스턴스는 신경 안씀.
2
lambda => 일반적으로 생각하는 함수 호출. 현재 콜스택 위에 쌓여서 실행.
proc => 블럭 안의 내용을 현재 실행 컨텍스트에 풀어가지고 실행하는 효과
함수형 프로그램밍을 할 수 있게 하는 특징 제공
🧸 일급객체
🧸 클로저
binding
x=1
y=2
b = binding
#=> binding 메소드 호출해서 b변수에 현재 실행 컨텍스트를 저장하는 바인딩 객체 저장
p b.class
p b.eval('x')
lambda, proc은 클로저 역할을 한다. lambda, proc이 생성된 컨텍스트에 대한 reference 가지고 있음. binding객체에 저장되어 있음.
def call_proc(my_proc)
count = 500
my_proc.call
end
count = 1
my_proc = Proc.new { puts count }
p call_proc(my_proc) # What does this print?
proc body의 count는 실행되는 컨텍스트인 500이 아니라 생성될때의 컨텍스트인 1인 정적 스코핑을 따름
🧸 currying => Proc클래스 curry 메소드
정리
===
* 참고..
yield_self -> 인스턴스 메소드. self(객체 자신)을 인자로 받아서 코드 블럭을 실행한 결과를 리턴 값으로 돌려줌.
메소드 chaining 할때 사용
Reference
https://www.rubyguides.com/2016/02/ruby-procs-and-lambdas/