함수형 프로그래밍

 💡 함수형 프로그래밍의 개념과 장점을 이해하고 다른 프로그래밍 방식과 차이를 이해하였습니다 !

 

함수형 프로그래밍

  • 함수형 프로그래밍은 대부분의 문제를 순수 함수로 나누어 해결하는 기법입니다.
  • 작은 문제를 해결하기 위한 함수를 작성하여 가독성을 높이고 유지보수를 용이하게 해줍니다.
  • 클린 코드의 저자 Robert C.Martin은 함수형 프로그래밍을 대입문이 없는 프로그래밍으로 정의하였습니다.
  • 명령형 프로그래밍 기반으로 개발할 때 소프트웨어의 크기가 커짐에 따라 발생하는 스파게티 코드의 유지보수 어려움을 해결하기 위해 사용되었습니다.
  • 선언형 프로그래밍의 방식입니다.

명령형 프로그래밍

  • 무엇(What)을 할 것인지 나타내기보다 어떻게(How)를 할 것인지 설명하는 방식입니다.
  • 아래 두 가지로 구분 됩니다.
    • 절차지향 프로그래밍: 수행되어야 할 순차적인 처리 과정을 포함하는 방식으로 C, C++이 있습니다.
    • 객체지향 프로그래밍: 객체들의 집합으로 프로그램의 상호작용을 표현하며 대표적으로 Java가 있습니다.

선언형 프로그래밍

  • 어떻게 할 것인지(How)를 나타내기보다 무엇(What)을 할 것인지를 설명하는 방식입니다.
  • 대표적으로 함수형 프로그래밍이 있으며, 원하는 결과를 묘사하는 방식으로 코드를 작성합니다.

동시성 문제 해결

  • 안정적인 소프트웨어를 개발하기 위해서 다양한 동시성 문제를 해결해야 합니다.
  • 데이터의 상태를 변경하는 객체지향 프로그래밍 방식으로는 동시성 문제를 해결하는 데 한계가 있으며, 함수형 프로그래밍으로 이를 해결할 수 있습니다.
  • 이는 불변성과 동시성과 관련이 있습니다.
    • 여러 스레드가 동일한 데이터에 접근해도 데이터가 변하지 않기 때문에 레이스 컨디션이나 데드락 같은 동시성 문제를 줄일 수 있습니다.
    • 비동기 작업에서 콜백이나 프로미스 같은 패턴을 자연스럽게 구현하여 작업이 완료되면 특정 함수를 호출하도록 코딩할 수 있습니다.

불변성

  • 데이터는 변경되지 않으며, 상태 변화를 피할 수 있습니다.

동시성

  • 여러 작업을 동시에 처리할 수 있습니다.

레이스 컨디션

  • 공유 자원에 대해 여러개의 스레드, 프로세스가 동시에 접근하는 경쟁 상태를 뜻합니다.

데드락

  • 두 개 이상의 작업이 서로 상대방의 작업이 끝나기 만을 기다리는 상태를 뜻합니다.

변경 불가능한 값을 활용

  • 값이 번경되는 것을 허용하면 멀티 스레드 프로그래밍이 어렵습니다.
  • 값을 변경할 수 없도록 하여 프로그램의 정확성을 높여 버그의 발생 가능성을 줄입니다.

참조 투명성

  • 동일한 인자에 대해 항상 동일한 결과를 반환하며, 기존의 값은 변경되지 않고 유지 됩니다.
  • 부작용을 제거하여 프로그램의 동작을 이해하고 예측이 가능한 프로그래밍을 할 수 있습니다 !

일급 객체로서의 함수

  • 함수가 일급 객체의 역할을 합니다.
  • 함수를 함수의 인자로 받거나 함수의 반환 값으로 활용하는 것이 가능해집니다.
  • 변수나 데이터 구조 안에 담을 수 있으며, 할당에 사용된 이름과 무관하게 고유한 구별이 가능합니다.

일급 객체?

  • 다른 객체들이 일반적으로 적용 가능한 연산을 모두 지원하는 객체이며 아래와 같은 특징을 가집니다.
    • 변수에 할당이 가능하다
    • 다른 함수의 인자로 전달 받는다
    • 다른 함수의 결과로서 리턴될 수 있다
fun applyOperation(x: Int, operation: (Int) -> Int): Int {
    return operation(x)
}

fun main() {
    val result = applyOperation(5, ::square) // square 함수를 인자로 전달
    println(result) // 출력: 25
}

순수 함수(Pure Function)

  • 부수효과를 제거한 함수들을 순수 함수라고 부릅니다.
  • Memory, I/O 관점에서 Side Effect가 없으며, 함수의 실행이 외부에 영향을 끼치지 않습니다.
  • 이는 Thread에 안전성을 보장하며 병렬 처리를 동기화 없이 진행할 수 있습니다.
fun square(x: Int): Int {
    return x * x
}

fun main() {
    println(square(4)) // 출력: 16
    println(square(4)) // 출력: 16
}

부수효과(Side Effect)

  • 부수효과란 아래와 같은 변화 혹은 변화가 발생하는 작업을 의미합니다.
    • 변수의 값이 변경
    • 자료 구조를 제자리에서 수정
    • 객체의 필드값 설정
    • 예외나 오류로 실행이 중단
    • 콘솔 또는 파일 I/O 발생

함수형 메서드를 활용한 데이터 처리

  • map, filter, reduce 등의 함수형 메서드를 활용하여 데이터를 처리할 수 있습니다.
fun main() {
    val numbers = listOf(1, 2, 3, 4, 5)

    // 각 요소를 제곱한 새로운 리스트 생성 (map 사용)
    val squares = numbers.map { it * it }

    // 짝수만 필터링 (filter 사용)
    val evenSquares = squares.filter { it % 2 == 0 }

    // 리스트의 모든 요소의 합 계산 (reduce 사용)
    val sumOfSquares = evenSquares.reduce { acc, i -> acc + i }

    println(squares) // 출력: [1, 4, 9, 16, 25]
    println(evenSquares) // 출력: [4, 16]
    println(sumOfSquares) // 출력: 20
}

참고

https://arc.net/l/quote/uakbmzuu

https://futurecreator.github.io/2018/10/05/why-functional-programming/