루비, 그루비, 클로저, 람다

www.slideshare.net/aalmiray/jfokus-functional-groovy에 나온 깔끔한 그루비 코드를 보고 루비로도 가능한지 궁금해졌습니다.

클로저는 아주 유용한 녀석입니다. 대체로 따로 선언해서 사용하기 보다는 루프나 함수호출에 인자로 전달하는 경우가 많고, 그래서 관련 문법을 잘 모르고 지나쳤었는데, 덕분에 한번 뒤져보았습니다.

첫번째 코드는 그루비의 클로저.

def dub = {int base, int factor ->
    base * factor
}
assert 4 == dub(2,2)
assert 4 == dub.call(2,2)

이걸 루비로 고쳐보면 다음과 같습니다.

a = lambda{|base,factor| base*factor}
puts a.call(2,3)
puts a.class
puts a[2,3]
puts a.(2,3)

루비에서는 클로저(람다)호출시에 “.call” 을 붙여야합니다. 아니면 “[]“라던가, 더 이상하게는 “.()“도 가능하고요. 그중에선 “call()“이 봐줄만합니다.

루비에서 람다 문법은 위의 것 말고, 화살표를 사용해서 정의하는 방식도 가능합니다. 아래쪽이 1.9에서 새롭게 지원되는 문법.

# a = lambda{|base,factor| base*factor} # 이것도 가능하고.
a = ->(base,factor) {base*factor} # 이것도 가능하고.

다음은 클로저의 특성중 하나인 자기가 실행되는 곳의 변수들에 접근 가능하다는 변수 스코프 예제.

// 그루비
int var = 0
def dub = { base, factor = 2->
    var = 42
    base * factor
}
assert 0 == var
assert 4 == dub(2,2)
assert 4 == dub.call(2,2)
assert 42 == var
print dub("hahah")

루비에서는 다음과 같습니다.

var = 0
#dub = ->(base, factor=2){
    dub = lambda{ |base, factor=2|
    var = 42
    base * factor
}
puts 0 == var
puts 4 == dub.call(2,2)
puts 42 == var
puts "hahahhahah" == dub.call("hahah")

변수스코프를 테스트하는 코드에, 인자 기본값도 테스트도 함께 넣었습니다. 자세히보면 두번째 인자 factor에 기본값을 주었습니다. 그리고, 루비/그루비 모두 변수 타입을 지정하지 않고 호출할 수 있는데, 마지막줄에서는 "hahah"*2 가 실행됩니다.

마지막은 그루비의 커리.

def m = {x, y -> y /x }
assert 1 == m(1,1)
assert 2 == m(1,2)
def at5 = m.curry(5)
assert 0.2 == at5(1)

동일한 루비 코드는 다음과 같습니다요.

m = lambda{|x,y| y.to_f/x}
puts 1 == m.call(1,1)
puts 2 == m.call(1,2)
at5 = m.curry[5]
puts 0.2 == at5.call(1)

그루비쪽이 “[]” 따위 이상한 문법을 쓰지 않고, 함수 호출처럼 쓸수있다는 점이 루비보다 좋아보이지만, 루비 코드도 계속 타이핑하다보면 익숙해집니다.

맨위에 링크에서는 그루비의 클로저 관련 문법들이 더 나옵니다만, 사실 그런 코드를 쓸일이 있을까 싶습니다. 여기에서 나온 코드들도 잘 안쓰는데 말이죠. 기본 문법은 꼭 필요한 개념들을 잘 지원해주는데 충실한 정도까지만, 그 이상 나가지는 말았으면 싶습니다. (만 그루비 구현하시는 분들 생각은 또 다르신듯.)