프로그래밍

함수형 프로그래밍

강철곰탱이 2024. 1. 3. 01:27

1. 프로그래밍 패러다임

 

 

프로그래밍 패러다임(Programming Paradigm)은 프로그래머에게 프로그래밍의 관점을 갖게 해주는 역할을 하는 개발 방법론이다.

 

명령형 vs 선언형

 

🏷 명령형

 

  • 컴퓨터에게 정확한 수행절차를 지시하는 방식
  • 프로그램이 "어떻게(How)" 수행되어야 하는지 설명

 

🏷 선언형

 

  • 어떻게 할지 명시하지 않고, 원하는 결과를 선언하는 방식
  • 프로그램이 "무엇을(What)" 수행할지에 대해 설명

 

 

📝 예시

 

배달음식 주문하기

 

  • 명령형(How): 배달 앱을 실행한다. 치킨을 골라서 장바구니에 담는다. 배달 받을 주소와 요청사항을 입력하고 치킨을 계산한다.  
  • 선언형(What):  치킨을 주문한다. 

 

물론 선언적 방식의 접근을 위해 "어떻게 접근하는 가"가 먼저 추상화되어있어야 한다.
=> 선언적 접근 방식의 기저에는 명령형이 깔려있고 추상화된 것이다.

 

 


 

2. 함수형 프로그래밍

 

 

함수형 프로그래밍은 선언형 패러다임의 일종이다. 

 

  • 작은 문제를 해결하기 위해 모든 것을 순수 함수로 나누어 문제를 해결하는 기법
  • "대입문이 없는 프로그래밍"
  • 같은 input에 동일한 output이 나온다. => 순수 함수
  • 예로 클로저, 하스켈, 리스프 등이 있다.

 

함수형 프로그래밍은 "순수 함수"들을 블록처럼 쌓아 로직을 구현하고 "고차 함수"를 통해 재사용성을 높인 프로그래밍 패러다임이다.

 

 

 

부수 효과(Side Effect)

 

: 함수가 실행되는 동안 그 외부에 영향을 미치는 모든 변화를 가리킨다.

 

  • 프로그램이 실행되는 동안 전역 변수나 외부 변수를 변경하는 경우
  • 예외를 발생시키거나 처리하는 동작

 

 

순수 함수(Pure Function)

 

  • 동일한 입력에 대해 항상 동일한 출력을 반환
  • Memory or I/O관점에서 side effect를 제거한 함수

 

func add(a: Int, b: Int) -> Int {
    return a + b
}

 

이 함수는 매개변수 a, b에만 영향을 받으므로 항상 동일한 결과를 반환하므로 순수 함수이다.

 

 

 

고차 함수(Higher-Order Function)

 

  • 함수를 다른 함수의 인자로 받거나, 함수를 반환하거나, 함수를 변수에 할당할 수 있는 함수
  • 함수를 1급 객체로 취급한다.
  • 예로 map, filter, reduce등이 있다.

 

let numbers = [1, 2, 3, 4, 5]
let result = numbers.map { $0 * $0 }
// result = [1, 4, 9, 16, 25]

 

map 함수는 배열의 각 요소에 함수를 적용하여 새로운 배열을 만드는 고차 함수이다.

 

 

 

1급 객체(First-Class Object)

 

  • 변수나 메서드에 함수를 할당할 수 있다.
  • 함수 안에 함수를 매개변수로 담을 수 있다.
  • 함수가 함수를 반환할 수 있다.

 

 

참조 투명성(Referential Transparency)

 

  • 동일한 입력에 대해 항상 동일한 출력을 반환
  • side effect가 없을 때 해당 함수는 참조적으로 투명하다고 할 수 있다.
  • 참조 투명성을 통해 기존의 값은 변경되지 않고 유지된다.(Immutable Data)

 

예를 들어, 다음 함수는 참조 투명하다고 할 수 있다.

func add(a: Int, b: Int) -> Int {
    return a + b
}

 

반면에 참조 투명하지 않은 함수는 외부의 상태나 외부의 다른 변수에 의해 결과가 영향을 받는다.

아래의 코드는 num이라는 전역변수를 두고 함수가 호출될 때마다 num의 값이 변하니 참조 투명하지 않다고 할 수 있다.

 

var num = 5

func add(a: Int) -> Int {
    num += a
    return num
}

 

 


🟢 장점

 

 

  • 불변성과 예측 가능성: 동일한 입력에 항상 동일한 출력을 반환하므로 예측 가능성이 높다.
  • 병렬 프로그래밍 용이성: 상태 변경이 없고 side effect가 적은 함수들로 이루어져 있어 병렬 처리가 더 쉽고 안전하게 이루어질 수 있다.
  • 테스트 용이성:각 함수가 독립적으로 동작하므로 테스트 간단하고 효과적으로 이루어진다. 
  • 재사용성 증가: 함수의 모듈성이 높아져 함수를 조합하여 큰 기능을 만들 수 있어 코드의 재사용성이 증가한다.

 

🔴 단점

 

  • 유연성 부족: 불변성을 유지하기 때문에 변수의 값을 변경하거나 갱신하는 것이 제한된다.

 


 

참고