더북(TheBook)

cos 함수의 두 인자가 각각 다른 괄호 안에 들어간다. compose 함수와 달리 higherCompose는 커리한 형태로 정의되어 있기 때문에 한 번에 하나씩 파라미터를 적용할 수 있다. 또한, 람다를 괄호 밖으로 빼내도 된다.9

val cos = higherCompose<Double, Double, Double>()()
    { x: Double -> Math.PI / 2 - x }(Math::sin)

지면 제약으로 한 줄을 넘어가 함수를 두 줄로 작성한 점을 제외하더라도, 마지막 부분은 약간 이상해 보인다. 하지만 코틀린에서는 이런 형식을 권장한다.10

 

익명 함수를 사용해야 하는 경우와 이름이 있는 함수를 사용해야 하는 경우

익명 함수를 사용할 수 없는 특별한 경우를 제외하면 이름이 있는 함수를 사용할지 익명 함수를 사용할지는 여러분의 선택에 달렸다(fun으로 정의한 함수는 항상 이름이 있다). 일반적인 규칙으로, 한 번만 사용하는 함수는 익명 함수로 정의하라. 하지만 한 번만 사용한다는 말은 함수를 한 번만 작성한다는 뜻이지 함수가 단 한 번만 인스턴스화된다는 뜻은 아니다.

다음 코드는 fun 함수를 사용해 Double 값의 코사인을 계산한다. 이 함수 구현은 람다 식과 함수 참조를 사용하므로 익명 함수를 2개 사용한다.

fun cos(arg: Double) = compose({ x -> Math.PI / 2 - x },Math::sin)(arg)

 

 


9 역주 모든 람다를 괄호 밖으로 뺄 수 있는 것은 아니다. 본문의 compose와 같이 인자가 여럿 있을 때는 맨 마지막 인자로 람다가 넘어가는 경우에만 그 람다를 괄호 밖으로 보낼 수 있다. 예를 들어 f를 먼저 적용하고 sin을 적용하는 compose를 작성하면 다음과 같다.

 

val fAndSin: (Double) -> Double = compose(Math::sin){ x: Double -> Math.PI / 2 - x }

 

10 역주 저자의 설명이 잘못됐다. 마지막 형태는 코틀린이 권장하는 형태가 아니다. 이 예제에서 ()()로 괄호가 두 번 온 것은 코틀린 문법의 모호성 때문이다. 코틀린은 괄호 밖으로 람다를 뺄 수 있게 하고, 함수의 유일한 인자가 람다인 경우에는 굳이 괄호를 쓰지 않고 중괄호만으로 람다를 인자로 넘길 수 있게 한다. 이로 인해 커리한 함수(또는 함수를 반환하는 fun 함수)에 인자를 연속으로 적용해야 하는 경우에는 람다 인자가 어떤 함수의 인자인지 판단하기 어려운 경우가 생긴다. 예를 들어 Int에서 Int로 가는 함수를 반환하는 함수를 생각해 보자.

 

val returnApplyN = { n: Int -> { f: (Int) -> Int -> f(n) } }
val apply10 = returnApplyN(10)
val twenty = apply10({ it + it }) // 20
val twenty2 = apply10 { it + it } // 20
val twenty3 = returnApplyN(10)({ it + it })
val twenty4Fail = returnApplyN(10){ it + it }

 

twenty4Fail에서 코틀린 컴파일러는 returnApplyN이 두 개의 인자를 받는 함수이고 { it + it }이라는 람다가 10에 이은 두 번째 인자라고 판단했다. 그래서 “error: too many argument…”라는 오류가 나온다. 하지만 실제로 이 람다는 returnApplyN을 적용한 결과로 나온 함수의 첫 번째 인자다. 이를 명확히 코틀린에게 알려주려면 적용 대상을 구분할 수 있게 괄호를 넣어야 한다.

val twenty4Success = (returnApplyN(10)) { it + it } // 20

 

마찬가지로 cos를 합성하는 예에서도 다음과 같이 적용 순서를 명확히 하고 괄호를 아예 없앨 수 있다.

val cos = (higherCompose<Double, Double, Double>())
  { x: Double -> Math.PI / 2 - x }(Math::sin)

 

본문에 있는 코드보다는 이 스타일의 코드를 사용하거나 아예 람다를 괄호 안에 넣는 편이 더 낫다.

신간 소식 구독하기
뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.