24.03.06 함수형 프로그래밍

KSang·2024년 3월 6일
0

TIL

목록 보기
82/101

함수형 프로그래밍이란 뭘까?

함수형 프로그래밍은 프로그래머가 프로그래밍의 관점을 갖게 하고 코드를 어떻게 작성할지 결정할때 도움을 주는 프로그래밍 패러다임이다.

우선 프로그래밍 패러다임을 알아보자.

최근 프로그래밍의 패러다임은 크게 2개로 구별된다.

  • 명령형 프로그래밍: 어떻게 할 건지를 설명하는 방식
    - 절차 지향 프로그래밍: 수행되어야 할 순차적인 처리 과정을 포함하는 방식(C,C++)
    - 객체 지향 프로그래밍: 객체들의 집합으로 프로그램의 상호작용을 표현 (C++,Java,C#)

  • 선언형 프로그래밍: 무엇을 할 건지를 설명하는 방식
    - 함수형 프로그래밍: 순수 함수를 조합하고 소프트웨어를 만드는 방식 (클로저, 하스켈, 리스프)

그 동안 안드로이드 개발 했던 것들은 전부 명령형 프로그래밍이라고 볼 수 있다 (컴포즈 제외)

여기서 함수형 프로그래밍이란 뭘까?

함수형 프로그래밍(FP)는 순수 함수를 사용해서 유지 관리가 가능한 소프트웨어를 만드는 소프트웨어 개발 접근 방식이다.
기능을 적용하고 구성해서 프로그램을 구축하는 것이다.

함수형 프로그래밍은 함수를 변수, 인수 및 반환 값으로 사용해서 깔끔한 코드를 생성한다.
또한 불변 데이터를 사용하고 공유 상태 같은 개념을 피한다.

객체 지향 프로그래밍에선, 변경 가능한 데이터와 공유 상태를 사용하는 점과 대조된다.

함수형 프로그래밍 언어는 명령문 실행보다는 선언과 표현식에 중점을 둔다.
인수로 전달하고, 다른 함수에서 반환하고, 이름에 연결한다.

FP는 프로세스가 아닌 결과에 중점을 두어, 루프 문 및 조건문 과 같은 반복은 지원하지 않는다.

C#, Java, JavaScript, PHP, Python을 비롯한 자주 사용되는 프로그래밍 언어 중 다수는 함수형 프로그래밍을 지원하거나 FP에 있는 기능을 사용한다.

순수 함수형 프로그래밍

순수 함수형 프로그래밍은 모든 함수를 결정론적 수학적 또는 순수 함수로 처리하는 함수형 프로그램의 하위 집합이다

결정론적 수학 함수에서 시스템의 미래 상태 개발은 임의성을 허용하지 않는대 반면
순수 함수는 동일한 인수에 대해 동일한 함수 반환값을 갖는다.
함수적용에 부작용도 없다

함수에 외부 코드를 삽입하면 프로그램에 부작용이 발생한다.

이로 인해 함수가 해당 작업을 제대로 수행하지 못하게 된다.

불순한 함수에는 하나 이상의 부작용이 있다.

fun updateMyAddress(newAddress) {

   val myAddress = [“ChurchSt”, “CovingtonCross”]

   myAddresses[myAddresses.length] = newAddress

   return myAddresses

}

코틀린 코드로 작성한 순수함수의 예제다.

외부 코드가 필요하지 않고 이는 순수한 기능을 의미한다.

불순한 함수형 프로그래밍(Impure Functional Programming)

val myAddresses = [“ChurchSt”, “CovingtonCross”]

fun updateMyAddress(newAddress) {

   myAddresses.push(newAddress)

   return myAddresses

}

이 코드는 외부 상태를 변경해 몇가지 부작용이 있다.

~~ 부작용

함수형프로그래밍이 중요한 이유

함수형 프로그래밍은 일반적으로 객체 지향 프로그래밍에 비해 덜 인기가 있었는데, 머신러닝과 빅데이터의 등장으로 최근 몇 년간 인기가 높아 졌다.

함수형 프로그래밍은 순수 함수를 효율적으로 병렬화하는 능력으로 유명하다.

함수형 프로그래밍 패러다임을 사용하면 데이터 분석 워크플로 및 작업을 위한 코드를 더 쉽게 분석, 테스트 및 유지 관리할 수 있다.

순수한 특성으로 인해 광범위한 데이터 세트와 기계 학습을 분석하는 데 이상적으로 적합하다.

순수 함수는 최종 결과에 영향을 미치는 외부 값 없이 항상 동일한 결과를 생성한다.

함수형 프로그래밍으로 생성된 알고리즘은 오류를 빠르게 식별하고 수정할 수도 있다.

많은 프로그래머와 소프트웨어 개발자는 순수한 기능 때문에 디버깅하기 쉬운 프로그래밍 패러다임으로 작업하는 것을 선호한다.

7가지 핵심 함수형 프로그래밍 개념

1. 순수기능

순수함수는 결정적이고 부작용이 없다.

하지만 목표는 부작용이 전혀 없는 코드를 만드는 것이 아니다

모든 프로그램은 API 호출 등 일종의 부작용을 수행해야 하기 때문에 모든 부작용을 제거하고 싶지 않다는 점을 이해하는 것이 중요하다.

부작용을 최소화 하여 프로그램의 동작을 더 쉽게 예측하고 테스트하는게 목표

var sessionState = "ACTIVE"

fun sessionIsActive(lastLogin: Date, expirationDate: Date): Boolean {
    if (lastLogin > expirationDate) {
        sessionState = "EXPIRED"
        return false
    }
    return true
}

val expirationDate = Calendar.getInstance().apply {
    set(2020, 10, 1)
}.time
val currentDate = Date()
val isActive = sessionIsActive(currentDate, expirationDate)

if (!isActive && sessionState == "ACTIVE") {
    logout()
}

여기서 발생한 부작용이 해 당 범위 외부의 변수를 수정한다.

이로 인해 함수 호출자에게 문제가 발생한다.

var sessionState = "ACTIVE"

fun sessionIsActive(lastLogin: Date, expirationDate: Date): Boolean {
    return lastLogin <= expirationDate
}

fun getSessionState(currentState: String, isActive: Boolean): String {
    if (currentState == "ACTIVE" && !isActive) {
        return "EXPIRED"
    }
    return currentState
}

val expirationDate = Calendar.getInstance().apply {
    set(2020, Calendar.NOVEMBER, 1)
}.time
val currentDate = Date()
val isActive = sessionIsActive(currentDate, expirationDate)
val newState = getSessionState(sessionState, isActive)

if (!isActive && sessionState == "ACTIVE") {
    logout()
}

sessionState = newState

여기선 함수가 새로운 상태를 반환하고, 그 반환값을 사용해서 상태를 업데이트한다.

그렇기 때문에 함수의 부작용을 줄이고, 함수의 순수성을 높였다.

2. 일급 함수

일급 함수의 또 다른 주요 이점은 함수 사용 방법에 대한 제한이나 제한이 없다는 것이다.

즉, 다른 변수처럼 동작하는 것 인대, 일급 함수는 커링, 고차 함수 및 클로저와 같은 다른 수정을 위한 기반을 마련한다.

3. 고차 함수

고차 함수는 함수를 인수로 사용하거나 함수를 반환 한다.

프로그램을 모듈화 하는 것 외에도 고차 함수를 사용해서 함수를 다형성으로 만들 수도 있다.

4. 불변성

불변 객체는 변경되지 않는다.

함수형 프로그래밍에서는 값이나 상태를 변경하지 않고 개체와 값을 초기화하고 구현한다.

필요한 경우 새 개체와 값을 만들 수 있지만 기존 개체나 값의 상태는 수정할 수 없다.

불변성 때문에 코드에서 문제가 발생하고 확산되는 것을 방지한다.

다중 스레드 응용 프로그램에서 스레드는 개체를 수정하는 사람이 없기 때문에 다른 스레드를 변경하지 않고 불변 개체에 대해 작업을 수행할 수 있다.

동시에 애플리케이션에서 코드의 오류를 방지한다.

5. 재귀

재귀는 함수가 자신을 호출할 때 발생하는대, 재귀 함수는 코드를 실행하고 종료 조건을 충족할 때까지 함수를 반복적으로 실행한다.
이 패턴은 표준 루프에서 찾을 수 있다.
루프는 초기 변수를 선언하고 변수를 사용하여 수행할 코드를 실행한다.

루프 대신 재귀를 사용할 수 있다. 하지만 루프는 결코 재귀를 대체할 수 없다.

6. 기능 구성

함수 합성을 사용하면 순수한 함수를 결합하여 더 복잡한 함수를 만들 수 있다.

코딩에서 여러 단계를 단일 코드 라인이나 새로운 기능으로 결합할 수 있다.

7. 참조 투명성

참조 투명성을 사용하면 값이 프로그램의 표현을 대체할 수 있다.

이 논리는 메서드가 추가 효과 없이 주어진 인수에 대해 항상 동일한 값을 반환해야 한다.

참조 투명성은 프로그램에 대한 추론을 보다 간단한 프로세스로 만든다.
각 하위 프로그램을 독립적으로 렌더링해서 리팩토링과 단위 테스트를 대폭 단순화 한다.

객체 지향프로그래밍과 함수형 프로그래밍

객체 지향 프로그래밍과 함수형 프로그래밍 사이에는 몇 가지 주요 차이점이 있지만 그 중 하나는 명령형 프로그래밍 모델과 선언적 프로그래밍 모델이다.

객체 지향에선 명령형 프로그래밍 모델을 사용한다
즉, 문제를 해결하는 데 필요한 모든 단계에서 함수가 변함없이 코딩된다.
문제 해결 방법을 지정하는 코드 자체를 사용해 각 작업을 코딩한다.
프로그래머는 문제를 해결할 수 있는 모델에 의존하는 대신 문제를 해결하는 데 어떤 기능이 필요한지 알아야 한다.

함수형에선 선언적 프로그래밍 모델을 사용한다.
프로그래밍 언어의 기본 개념을 사용해 미리 결정된 결과에 도달하는데 필요한 단계를 실행한다.

명령형 프로그램은 문제 해결의 단계별 과정에 초점을 맞추는 반면, 선언형 프로그램은 문제 해결의 결과에 초점을 맞춘다.

또 다른 차이점은 가변성이다.
객체 지향은 가변 데이터를 사용하는 반면 함수형은 불변 데이터를 사용한다.

변경 가능한 객체는 생성 후에 변경 할 수있지만 불변 객체는 변경이 불가능 하다.

전반적으로 불변 코드는 업데이트가 쉽고, 관리가 효율적이며, 테스트 및 디버그가 쉽다.

그리고 변수가 일정하기 때문에 결과 코드를 이해하고 추론하기 쉽다.

객체 지향은 표준화되고 간단한 프로젝트에 가장 적합한 반면
함수형은 확장성과 유연성이 필요한 프로젝트에 가장 적합하다.

함수형 프로그래밍이 미래다..

0개의 댓글