본문 바로가기

Kotlin

[Kotlin] 함수형 프로그래밍

안녕하세요.

오늘은 함수형 프로그래밍에 대해 알아보겠습니다


함수형 프로그래밍

코틀린은 함수형 프로그래밍을 지원하는 언어입니다

함수형 프로그래밍
- 함수를 일급 시민으로 취급
- 함수를 변수처럼 다루고,
- 고차 함수를 통해 다른 함수의 인자로 넘기거나 반환 값으로 사용할 수 있음

특징

함수형 프로그래밍의 특징을 알아보도록 하겠습니다

 

1) 순수 함수

같은 입력에 대해 항상 같은 출력을 반환하는 함수입니다

외부 상태나 함수 외부에 영향을 받지 않는 함수입니다

fun add(a: Int, b: Int): Int = a + b

 

2) 불변성

함수형 프로그래밍에서는 변수를 변경하지 않고 새로운 값을 생성하여 사용합니다

불변 데이터는 코드의 안정성을 높이고, 데이터 경쟁을 방지하는데 유용합니다 (특히, 동시성 프로그래밍에서)

// 불변성 예제: 주어진 숫자 리스트에서 짝수만 필터링하고 제곱을 계산
fun squareOfEvenNumbers(numbers: List<Int>): List<Int> {
    return numbers.filter { it % 2 == 0 } // 짝수만 필터링
                  .map { it * it }        // 제곱 계산
}

fun main() {
    val numbers = listOf(1, 2, 3, 4, 5)
    val result = squareOfEvenNumbers(numbers)
    println(result) // [4, 16]
}

 

3) 고차 함수

함수을 인자로 받거나, 함수 자체를 반환할 수 있는 함수입니다

이를 통해 기능을 캡슐화하고 재사용성을 높일 수 있습니다

// 고차 함수 예제: 연산 함수를 인자로 받아 두 숫자를 연산
fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
    return operation(a, b)
}

fun main() {
    val sum = calculate(3, 4) { x, y -> x + y }
    val product = calculate(3, 4) { x, y -> x * y }
    println("Sum: $sum, Product: $product") // Sum: 7, Product: 12
}

 

4) 람다 표현식

간결하게 함수를 작성할 수 있는 구문입니다

일회성 또는 간단한 함수를 표현할 때 유용합니다

fun main() {
    val numbers = listOf(1, 2, 3, 4, 5)
    
    // 짝수만 필터링하여 출력
    val evenNumbers = numbers.filter { it % 2 == 0 }
    println(evenNumbers) // [2, 4]
}

 

5) 함수 합성

작은 함수들을 조합하여 더 복잡한 함수나 작업을 수행하는 방법입니다

이를 통해 간결하고 직관적인 코드 작성이 가능합니다

// 개별 기능 함수
fun double(x: Int) = x * 2
fun increment(x: Int) = x + 1

// 함수 합성: double과 increment를 순서대로 실행하는 함수 생성
fun compose(f: (Int) -> Int, g: (Int) -> Int): (Int) -> Int {
    return { x -> f(g(x)) }
}

fun main() {
    val doubleAfterIncrement = compose(::double, ::increment)
    println(doubleAfterIncrement(5)) // (5 + 1) * 2 = 12
}

예시

복잡한 예시를 통해 함수형 프로그래밍의 유용성을 알아보도록 하겠습니다

 

예제 : 특정 조건의 직원 평균 연봉 구하기

 

요구 사항

  • 모든 직원의 부서별 평균 연봉을 계산
  • 평균 연봉이 600만원 이상인 부서만 필터링
  • 필터링된 부서의 평균 연봉을 기준으로 상여금 (10%)을 추가로 계산하여 리스트로 반환

1) 데이터 모델 정의

data class Employee(
    val name: String,
    val age: Int,
    val department: String,
    val salary: Double // 월급(단위: 만 원)
)

val employees = listOf(
    Employee("Alice", 28, "Development", 350.0),
    Employee("Bob", 32, "Management", 500.0),
    Employee("Charlie", 40, "CTO", 750.0),
    Employee("Dave", 35, "Development", 420.0),
    Employee("Eve", 29, "Design", 380.0),
    Employee("Frank", 45, "Management", 700.0),
    Employee("Grace", 30, "Design", 450.0)
)

 

2) 요구 사항을 함수형 프로그래밍으로 해결하기

fun calculateFilteredDepartmentSalaryWithBonus(
    employees: List<Employee>,
    minAverage: Double,
    bonusRate: Double
): Map<String, Double> =
    employees.groupBy { it.department }
        .mapValues { (_, empList) -> empList.map { it.salary * 12 }.average() }
        .filter { (_, averageSalary) -> averageSalary >= minAverage }
        .mapValues { (_, averageSalary) -> averageSalary * (1 + bonusRate) }

fun main() {
    val result = calculateFilteredDepartmentSalaryWithBonus(employees, minAverage = 600.0, bonusRate = 0.1)

    println("평균 연봉 600만 원 이상 부서의 상여금 포함 연봉: ")

    // flatMap을 사용하여 결과를 리스트로 변환 후 하나씩 출력
    result.flatMap { (department, salaryWithBonus) ->
        listOf("부서: $department, 상여금 포함 연봉: ${salaryWithBonus}만 원")
    }.forEach { println(it) }
}

 

3) 결과

평균 연봉 600만 원 이상 부서의 상여금 포함 연봉: 
부서: Development, 상여금 포함 연봉: 5082.0만 원
부서: Management, 상여금 포함 연봉: 7920.000000000001만 원
부서: CTO, 상여금 포함 연봉: 9900.0만 원
부서: Design, 상여금 포함 연봉: 5478.0만 원

 

'Kotlin' 카테고리의 다른 글

[Kotlin] DSL (Domain Specific Language)  (0) 2024.11.05
[Kotlin] SAM & invoke  (1) 2024.10.30
[Kotlin] Scope Function  (2) 2024.10.11
[Kotlin] Sealed Class  (3) 2024.09.22
[Kotlin] Extension Function (확장 함수)  (0) 2024.09.10