함수형 패러다임에서는 OOP Style 로 변수들을 모아두는 대신, closure 캡쳐식으로 유지하는데, 보통 Currying 이 자동으로 적용되서, 부분함수를 쉽게 만들수 있다.
let add (a: int) (b: int) = a + b
let addOne = add 1
let result = addOne 2
parameter 2개를 받는 함수 add 에 파라미터를 한개만 넣으면, 자동으로 해당 값은 캡쳐되고 파라미터 한개를 받는 함수 (부분적 으로 적용된 함수 -> 즉 부분 함수 PartialFunction이다 )
그리고 이렇게 걍 파라미터를 들 적으면 알아서 부분함수가 되는게 Currying 이라고 한다.
Kotlin 은 어디까지나 기본 철학은 OOP 위에 쌓여있는 언어이기 때문에 Currying 이 자동으로 되지는 않는데, 적당히 람다나 inner function 을 리턴하는 식으로 직접 Currying 용 함수를 만들 수 는 있다.
fun add (a:Int) : (Int) -> Int {
fun b (c:Int) : Int {
return a + c
}
return ::b
}
val add1 = add(1)
val result = add1(2)
Kotlin 의 DSL 구축을 위한 여러 Feature 를 쓰까섞어서 멋들어진 코드를 작성할 수 있는데,
여기서 Generic Function 에 대한 부분 함수 처리에서 문제가 발생한다.
예를 들어 Currying 을 적용한 이후 Int가 아닌 T를 받는 함수를 만들고 싶다고 해보자
fun<T> add (a:Int) : (T) -> Int {
fun b (c:T) : Int {
if (c is String)
return a + c.toInt()
if (c is Int)
return a + c
return 0
}
return ::b
}
val add1 = add<Int>(1) // 여기서 Type 을 정해야함!
val result = add1(2)
val result = add2("2") // 불가능!
변수(런타임)와 코드(컴파일타임)의 실체화 시간이 다르기 때문에
이렇게 add1 이라는 Generic 함수를 만들수 없고, add1 은 Geneic 함수가 아닌, Generic 을 통해 만들어진, "Int' 만 받는 함수가 된다.
해결방법은? 딱히 없다... 따라서 좀 Tricky 하게 해결해야 하는데... 바로 Invoke 오퍼레이터를 이용한 짭 함수를 만드는것..
data class Add(val a: Int) {
operator fun<T> invoke(b: T): Int {
if (b is String)
return a + b.toInt()
if (b is Int)
return a + b
return 0
}
}
fun add (a:Int): Add {
return Add(a)
}
val add1 = add(1)
val result = add1(2)
val result2 = add1("2")
이런식으로 구현 할 수 있다. (이 경우에는 쓸모없는 add 함수를 지우고 Add class 명을 add 로 바꿔도 동일한 동작)
참고로 Kotlin 보다 더 FP 에 근간을 둔 F# 에서도 Generic Function 을 부분함수화 시키는건 안되더라..
F# 에서는 다음과 같이 해결한다.
let add (a: int) (b: 't) =
match box b with
| :? int as i -> a + i
| :? string as s -> a + int s
| _ -> 0
let add1 b = add 1 b
add1 2
add1 "2"
그냥 함수를 새로 만든다 ;; 엄밀히 말하면 currying 은 아니고 그냥 함수인데 타입추정에 의하여 쉽게 bake 하는 방법..
'프로그래밍 기술 노트 > Functional Study' 카테고리의 다른 글
[Monad] 내멋대로 Monad 이해하기 - Kleisli🐟 (0) | 2024.09.06 |
---|---|
[Algebraic Effect] 내 멋대로 대수적 효과 이해하기 feat Continuation (3) | 2022.12.15 |
[함수형 미세 팁] 파라미터 3개 이상의 Function 으 로 Reduce 하기 (1) | 2022.12.09 |
[liftIO] 빠르게 올리는 함수형 컨퍼런스 liftIO 2022 후기 (0) | 2022.12.03 |
Delimited Continuations 가 대체 뭔데? (1) | 2022.10.14 |