Zum Hauptinhalt springen

🎭 고차 함수

📖 고차 함수란?

**고차 함수(Higher-Order Function)**는 함수를 인자로 받거나 함수를 반환하는 함수입니다. Kotlin의 함수형 프로그래밍 핵심입니다!

💡 기본 개념

함수를 인자로

fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
return operation(a, b)
}

fun main() {
// 람다 전달
val sum = calculate(5, 3) { x, y -> x + y }
println(sum) // 8

val product = calculate(5, 3) { x, y -> x * y }
println(product) // 15
}

함수를 반환

fun makeMultiplier(factor: Int): (Int) -> Int {
return { number -> number * factor }
}

fun main() {
val double = makeMultiplier(2)
val triple = makeMultiplier(3)

println(double(5)) // 10
println(triple(5)) // 15
}

🔧 내장 고차 함수

filter

조건에 맞는 요소만 필터링

fun main() {
val numbers = listOf(1, 2, 3, 4, 5, 6)

// 짝수만
val evens = numbers.filter { it % 2 == 0 }
println(evens) // [2, 4, 6]

// 3보다 큰 수
val greaterThan3 = numbers.filter { it > 3 }
println(greaterThan3) // [4, 5, 6]
}

map

각 요소를 변환

fun main() {
val numbers = listOf(1, 2, 3, 4, 5)

// 제곱
val squared = numbers.map { it * it }
println(squared) // [1, 4, 9, 16, 25]

// 문자열로
val strings = numbers.map { "숫자: $it" }
println(strings) // [숫자: 1, 숫자: 2, ...]
}

forEach

각 요소에 작업 수행

fun main() {
val fruits = listOf("사과", "바나나", "포도")

fruits.forEach { fruit ->
println("과일: $fruit")
}
// 과일: 사과
// 과일: 바나나
// 과일: 포도
}

reduce

요소들을 누적 계산

fun main() {
val numbers = listOf(1, 2, 3, 4, 5)

// 합계
val sum = numbers.reduce { acc, num -> acc + num }
println(sum) // 15

// 최댓값
val max = numbers.reduce { acc, num ->
if (num > acc) num else acc
}
println(max) // 5
}

fold

초기값과 함께 누적

fun main() {
val numbers = listOf(1, 2, 3, 4, 5)

// 초기값 0에서 시작
val sum = numbers.fold(0) { acc, num -> acc + num }
println(sum) // 15

// 초기값 10에서 시작
val sumWith10 = numbers.fold(10) { acc, num -> acc + num }
println(sumWith10) // 25
}

🎯 실전 예제

커스텀 필터 함수

fun <T> customFilter(list: List<T>, predicate: (T) -> Boolean): List<T> {
val result = mutableListOf<T>()
for (item in list) {
if (predicate(item)) {
result.add(item)
}
}
return result
}

fun main() {
val numbers = listOf(1, 2, 3, 4, 5, 6)

val evens = customFilter(numbers) { it % 2 == 0 }
println(evens) // [2, 4, 6]

val greaterThan3 = customFilter(numbers) { it > 3 }
println(greaterThan3) // [4, 5, 6]
}

조건 체이닝

fun main() {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

val result = numbers
.filter { it % 2 == 0 } // 짝수만
.map { it * it } // 제곱
.filter { it > 10 } // 10보다 큰 것만
.sorted() // 정렬

println(result) // [16, 36, 64, 100]
}

유효성 검사

fun validateInput(
input: String,
validators: List<(String) -> Boolean>
): Boolean {
return validators.all { validator -> validator(input) }
}

fun main() {
val password = "Password123"

val isValid = validateInput(password, listOf(
{ it.length >= 8 }, // 8자 이상
{ it.any { c -> c.isDigit() } }, // 숫자 포함
{ it.any { c -> c.isUpperCase() } } // 대문자 포함
))

println(if (isValid) "유효한 비밀번호" else "유효하지 않음")
}

데이터 변환 파이프라인

data class Person(val name: String, val age: Int)

fun main() {
val people = listOf(
Person("Alice", 25),
Person("Bob", 30),
Person("Charlie", 20),
Person("David", 35)
)

// 30세 이상의 이름만 대문자로
val result = people
.filter { it.age >= 30 }
.map { it.name.uppercase() }
.sorted()

println(result) // [BOB, DAVID]
}

🔍 고급 활용

함수 조합

fun <T, R, V> compose(
f: (R) -> V,
g: (T) -> R
): (T) -> V {
return { x -> f(g(x)) }
}

fun main() {
val addOne = { x: Int -> x + 1 }
val double = { x: Int -> x * 2 }

// 먼저 1을 더하고, 그 다음 2를 곱함
val addThenDouble = compose(double, addOne)

println(addThenDouble(5)) // (5 + 1) * 2 = 12
}

부분 적용

fun partial(a: Int, operation: (Int, Int) -> Int): (Int) -> Int {
return { b -> operation(a, b) }
}

fun main() {
val add5 = partial(5) { a, b -> a + b }
val multiply3 = partial(3) { a, b -> a * b }

println(add5(10)) // 15
println(multiply3(4)) // 12
}

repeat 함수

fun repeat(times: Int, action: (Int) -> Unit) {
for (i in 0 until times) {
action(i)
}
}

fun main() {
repeat(5) { index ->
println("반복 $index")
}
// 반복 0
// 반복 1
// 반복 2
// 반복 3
// 반복 4
}

📊 성능 최적화

sequence로 지연 평가

fun main() {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

// 일반 리스트 (즉시 평가)
val result1 = numbers
.filter { println("filter: $it"); it % 2 == 0 }
.map { println("map: $it"); it * it }
.take(2)

println()

// Sequence (지연 평가)
val result2 = numbers.asSequence()
.filter { println("filter: $it"); it % 2 == 0 }
.map { println("map: $it"); it * it }
.take(2)
.toList()
}

🤔 자주 묻는 질문

Q1. 고차 함수는 왜 사용하나요?

A: 코드 재사용과 추상화!

// ❌ 중복 코드
fun getEvens(list: List<Int>) = list.filter { it % 2 == 0 }
fun getOdds(list: List<Int>) = list.filter { it % 2 != 0 }

// ✅ 고차 함수로 재사용
fun filterBy(list: List<Int>, condition: (Int) -> Boolean) =
list.filter(condition)

fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
val evens = filterBy(numbers) { it % 2 == 0 }
val odds = filterBy(numbers) { it % 2 != 0 }
}

Q2. 언제 사용하면 좋나요?

A: 반복되는 패턴을 추상화할 때!

// 여러 곳에서 비슷한 작업
fun processUsers() {
// 로그 시작
println("처리 시작")
// 실제 작업
println("사용자 처리")
// 로그 종료
println("처리 완료")
}

// ✅ 고차 함수로 추상화
fun withLogging(action: () -> Unit) {
println("처리 시작")
action()
println("처리 완료")
}

fun main() {
withLogging {
println("사용자 처리")
}
}

Q3. 성능에 문제는 없나요?

A: 대부분 무시할 정도! 가독성이 더 중요합니다.

// 성능은 거의 같음
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)

// 일반 반복문
val result1 = mutableListOf<Int>()
for (num in numbers) {
if (num % 2 == 0) {
result1.add(num * 2)
}
}

// 고차 함수 (더 읽기 쉬움!)
val result2 = numbers
.filter { it % 2 == 0 }
.map { it * 2 }
}

🎬 마치며

고차 함수로 표현력 있는 코드를 작성하세요!

핵심 정리:
✅ 함수를 인자로 받거나 반환
✅ filter, map, reduce 등 활용
✅ 코드 재사용과 추상화
✅ 체이닝으로 깔끔한 처리
✅ 함수형 프로그래밍의 기초

다음 단계: 스코프 함수에서 let, apply 등을 알아보세요!