Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

Scala의 Function Value와 Closures

Functional 프로그래밍에서 function는 first-class이기 때문에 function을 파라미터로 function에 전달하거나 리턴받을수 있고 function안에 중첩시킬수도 있습니다.  이러한 것을 function values라고 부르는데 function value는 실제로 object입니다. 스칼라에서는 익명함수를 함수에 전달할수 있기 때문에 로직을 파라미터로 전달하여 재사용할 수 있으며 이렇게 파라미터로 함수를 받는 함수를 고수준함수(Higher-order function)이라고 합니다.


Function Value

def sum(fv: Int => Int) : Int = {
    var total = 0
    for (i <- 1 to 10) {
        total += fv(i)
    }
    total
}

sum(a => a) // 55
sum(a => a*2) // 110

펑션밸류를 사용하면 위처럼 로직을 재사용할 수 있게 됩니다. 위에서 사용한 평션밸류를 val t = { (a:Int, b:Int) => a + b }처럼 변수로 정의해서 전달할 수도 있습니다만 이렇게 별로도 정의해서 사용할때는 타입추론이 불가능하므로 파라미터의 타입을 명시해 주어야 합니다.



Currying
커링은 1개 이상의 파라미터를 받는 함수를 다수의 파라미터 리스트를 받는 함수로 바꿔줍니다.
여러개의 파라미터를 가진 1개의 파라미터 리스트를 받는 메서드를 작성하는 대신 각각 1개의 파라미터를 가지는 여러개의 파라미터 리스트를 작성할 수 있습니다. 이 말은 def foo(a: Int, b: Int, c: Int){} 대신에 def foo(a: Int)(b: Int)(c: Int){}로 작성할 수 있고 이는 foo(1)(2)(3), foo(1){2}{3}, foo{1}{2}{3}과 같이 호출할 수 있습니다.

scala>def foo(a: Int)(b: Int)(c: Int) {}
foo: (Int)(Int)(Int)Unit

scala> foo _
res1: (Int) => (Int) => (Int) => Unit = <function>

위 코드에서 foo _로 호출하면 partially applied function가 생성되는데 각 체인에서 Int를 받고 Partially Applied Function을 리턴합니다.  마지막 결과는 Unit안에 담깁니다. curry를 할때 Partially Applied Function의 생성은 스칼라 내부의 작업입니다.


def sum()(fv: Int => Int) : Int = {
    var total = 0
    for (i <- 1 to 10) {
        total += fv(i)
    }
    total
}

sum(){a => a} // 55
sum(){a => a*2} // 110

앞의 정의한 예제를 다시 작성하면 위와같이 커링을 사용할 수 있습니다.



파라미터의 위치표기법(Positional Notation)

val array = Array(1,2,3,4,5)
val fv = { (a:Int, b:Int) => a + b }

val result = (0 /: array){ (a,b) => fv(a, b) } // 15
val result = (0 /: array){ fv(_, _) }
val result = (0 /: array){ fv }

언더스코어(_)를 function value의 파라미터들을 순서대로 매칭해서 사용할 수 있습니다. 파라미터 전체를 받을때는 언더스코어(_)를 하아예 써주지 않아도 됩니다. /:() 는 foldLeft()의 별칭이고 foldRight()는 \:()로 사용합니다.




Partially Applied Function

def show(a:String, b:String) { println(a + " and " + b) }
val partiallyShow = show("Outsider", _:String)

partiallyShow("SpringSprout") 
partiallyShow("FRENDS") 

// output
// Outsider and SrpingSprout
// Outsider and FRENDS

함수에 파라미터들 중 일부만 전달하고 나머지는 언더스코어(_)로 처리하면 Partially Applied Function을 돌려받고 위처럼 나중에 나머지 파라미터를 전달해서 다시 사용할 수 있습니다.
2010/06/14 04:15 2010/06/14 04:15