관리 메뉴

The Nirsa Way

[Kotlin] 람다(Lambda)와 고차 함수(Higher-Order Function) 예시 본문

Development/Kotlin

[Kotlin] 람다(Lambda)와 고차 함수(Higher-Order Function) 예시

KoreaNirsa 2025. 8. 22. 13:09
반응형
※ 해당 코틀린 포스트들은 기본적으로 자바를 알고 있다는 가정하에 간단히 예제만 제공하여 설명됩니다.

 

람다(Lambda)와 고차 함수(Higher-Order Function) 예시

이번 포스팅에서는 코틀린 기준의 람다와 고차함수에 대해 정리합니다. 기본적인 개념은 람다는 이름없는 함수, 고차 함수는 매개변수 또는 반환 값이 함수인 것을 뜻합니다. 아래의 예시를 보며 람다와 고차 함수를 하나씩 확인하도록 하겠습니다.

 

1. 람다 예시

람다의 경우 이름 없는 함수로써 아래와 같이 표현될 수 있습니다. 아래의 코드를 확인해보면 square(5)를 호출하고 있는데, (Int) 부분이 매개변수의 타입을 뜻하며 -> Int는 반환 타입을 뜻합니다.

fun main() {
    // val 변수명: 매개변수타입 -> 반환타입 = { 매개변수명 -> 코드 }           
    val square: (Int) -> Int = { x -> x * x }
    println(square(5)) // 25
}

만약 매개변수가 여러개인 상황과 없는 상황을 보면 아래와 같이 활용이 가능합니다. 

// 매개변수 2개, Int 두 개 받아 Int 반환
val sum: (Int, Int) -> Int = { a, b -> a + b }
println(sum(2, 3)) // 5

// 매개변수 없음, Unit 반환(출력만)
val greet: () -> Unit = { println("hi") }

또한 블록 안에 여러 줄의 코드가 들어갈 경우 반환할 변수(또는 값)를 마지막 줄에 작성하면 return을 명시하지 않고 반환됩니다.

// 블록 본문: 마지막 표현식이 반환값
val squareVerbose: (Int) -> Int = { x ->
    val r = x * x
    r   // 이 줄이 반환됨
}

 

2. 람다 + 고차함수 예시

첫번째로 아까 사용했던 sum을 활용하여 고차 함수를 작성하도록 하겠습니다. 람다는 이름 없는 함수였으며, 고차 함수는 매개변수로 함수를 받거나 반환을 함수로 하는 것이였습니다.

// 매개변수 2개, Int 두 개 받아 Int 반환
val sum: (Int, Int) -> Int = { a, b -> a + b }
println(sum(2, 3)) // 5

아래의 코드를 확인해 보면 람다로 작성된 sum을 인자로 넘겼으며, OperateTwoNumbers 메서드가 함수를 매개변수로 받으므로 이는 고차함수라고 볼 수 있습니다.

// 고차 함수: (Int, Int) -> Int 타입의 함수를 받아서 실행
//                              고차함수명: 매개변수타입 -> 반환값
fun operateTwoNumbers(a: Int, b: Int, op: (Int, Int) -> Int): Int {
    return op(a, b) // 전달받은 함수 호출
}

fun main() {
    val sum: (Int, Int) -> Int = { a, b -> a + b }
    println(operateTwoNumbers(2, 3, sum)) // 5
}

 

두번째로 위에서 사용했던 greet을 활용하여 고차 함수를 작성하도록 하겠습니다. 기존 작성했던 람다(greet)는 아래와 같습니다.

// 매개변수 없음, Unit 반환(출력만)
val greet: () -> Unit = { println("hi") }

고차함수는 마찬가지로 함수로 전달받아 구현부 { } 블록 내에서 호출하여 사용합니다.

// 고차 함수: () -> Unit 타입의 함수를 받아서 호출
//       고차함수명: 매개변수타입 -> 반환타입
fun runAction(action: () -> Unit) {
    println("Before action")
    action() // 전달받은 함수 호출
    println("After action")
}

fun main() {
    val greet: () -> Unit = { println("hi") }
    runAction(greet)
}

중간에 전달받은 함수가 실행되므로 action()이 호출되며 "hi"가 출력될 것 입니다. 전체적인 출력은 아래와 같습니다.

Before action
hi
After action

 

마지막으로 squareVerbose를 고차 함수로 작성하도록 하겠습니다. 기존 작성했던 람다(squareVerbose)는 아래와 같습니다.

// 블록 본문: 마지막 표현식이 반환값
val squareVerbose: (Int) -> Int = { x ->
    val r = x * x
    r   // 이 줄이 반환됨
}

고차 함수를 작성하면 아래와 같이 되는데 리스트(1, 2, 3, 4)를 첫번째 인자로 전달하고, 람다로 작성한 squareVerbose를 두번째 매개변수로 전달합니다.

고차 함수 applyAndPrintAll 내에서 전달받은 리스트를 하나씩 for문으로 꺼내고, 전달받은 함수에 꺼낸 값을 인자로 보내 실행합니다.

그렇다면 처음 for문이 돌 때는 1을 squareVerbose에 전달하여 val r = 1*1이 되어 반환 값은 1이며, 그 다음 for문이 돌 때는 2를 squareVerbose에 전달하여 var r = 2*2가 되어 반환 값은 4가 될 것입니다.

// 고차 함수: (Int) -> Int 타입을 받아서 여러 값에 적용
fun applyAndPrintAll(values: List<Int>, op: (Int) -> Int) {
    for (v in values) {
        println("Input: $v, Output: ${op(v)}")
    }
}

fun main() {
    val squareVerbose: (Int) -> Int = { x ->
        val r = x * x
        r   // 마지막 표현식이 반환값
    }
    applyAndPrintAll(listOf(1, 2, 3, 4), squareVerbose)
}

이렇게 1~4까지 for문이 모두 실행되었다면 출력 값은 아래와 같습니다.

Input: 1, Output: 1
Input: 2, Output: 4
Input: 3, Output: 9
Input: 4, Output: 16
반응형