[CS] 함수형 프로그래밍(Functional Programming)이란?

아이엠강욱·2023년 4월 9일
0

1. 프로그래밍 패러다임 (Programming Paradigm)

프로그래밍 패러다임은 프로그래머에게 프로그래밍의 관점을 갖게 하고 코드를 어떻게 작성할 지 결정하는 역할을 합니다. 새로운 프로그래밍 패러다임을 통해서는 새로운 방식으로 생각하는 법을 배우게 되고, 이를 바탕으로 코드를 작성하게 됩니다.

최근의 프로그래밍 패러다임은 아래와 같이 구분할 수 있습니다.

  • 명령형 프로그래밍: 무엇(What)을 할 것인지 나타내기보다 어떻게(How) 할 건지를 설명하는 방식

    • 절차지향 프로그래밍: 수행되어야 할 순차적인 처리 과정을 포함하는 방식 (C, C++)
    • 객체지향 프로그래밍: 객체들의 집합으로 프로그램의 상호작용을 표현하는 방식 (Java)
  • 선언형 프로그래밍: 어떻게(How) 할 건지를 나타내기 보다 무엇(What)을 할 건지를 설명하는 방식

    • 함수형 프로그래밍: 순수 함수를 조합하고 소프트웨어를 만드는 방식 (클로저)

2. 함수형 프로그래밍의 등장

명령형 프로그래밍을 기반으로 개발했던 개발자들은 개발하는 소프트웨어의 크기가 커지면서 복잡하게 엉켜있는 코드를 유지 및 보수하는 것이 매우 힘들다는 것을 느끼게 됩니다. 이 문제를 해결하기 위해 함수형 프로그래밍이라는 프로그래밍 패러다임에 관심을 갖게 되었습니다.

함수형 프로그래밍은 거의 모든 것을 순수 함수로 나누어 문제를 해결하는 기법으로 작은 문제를 해결하기 위한 함수를 작성하여 가독성을 높이고 유지보수를 용이하게 해줍니다.

실제로 개발자들이라면 거의 다 알고 있는 클린코드의 저자인 Robert C.Martin은 함수형 프로그래밍을 대입문이 없는 프로그래밍이라고 정의했습니다.

저만 그런지는 모르겠지만... 대입문이 없는 프로그래밍이라는 워딩의 의미를 이해하기가 조금 힘들었습니다. 하지만 아래의 아주 간단한 예시만 들었더니 약간의 감은 잡혔습니다.

아래의 코드 예시와 같은 간단한 코드에도 변수가 할당되고 값이 대입되고 있습니다.

// 1부터 10까지의 값이 i에 할당(대입)되고 있다.
for(int i = 1; i < 10; i++) {
    System.out.println(i);
}

3. 함수형 프로그래밍에 대한 이해

함수형 프로그래밍은 대입문을 사용하지 않는 프로그래밍이며 작은 문제를 해결하기 위한 함수를 작성합니다. 따라서 위의 코드를 다음과 같이 작성할 수 있습니다.

// 함수형 프로그래밍의 이해를 돕기위한 수도코드입니다.
process(10, print(num));

process 함수는 첫 번째 인자로 몇까지 iteration을 돌 것인가를 매개변수로 받고 있고, 두 번째 인자로 전달받은 값을 출력하라는 함수를 매개변수로 받고 있습니다.

위의 내용에서도 언급하듯 함수형 프로그래밍은 무엇(What)에 포커스를 두는 프로그래밍이라고 말씀드렸습니다. 따라서 함수형 프로그래밍에서는 출력을 하는 함수를 파라미터로 넘길 수 있습니다.

이는 함수형 프로그래밍의 기본 원리 중에서 함수를 1급 시민(First-Class Citizen) 또는 1급 객체(First-Class Object)로 관리하는 특징 때문입니다. 이에 대한 내용은 뒤에 설명드리도록 하겠습니다.

명령형 프로그래밍에서는 메서드를 호출하면 코드 작성 스타일에 따라 내부의 값이 바뀔 가능성이 있습니다. 이는 우리가 개발한 함수 내에서 선언된 변수의 메모리에 할당된 값이 바뀌는 등의 변화가 발생할 수 있다는 의미입니다.

하지만 함수형 프로그래밍에서는 대입문이 없기 때문에 메모리에 한 번 할당된 값은 새로운 값으로 변할 수 없게 됩니다.


4. 함수형 프로그래밍의 특징

부수효과가 없는 순수 함수를 1급 객체로 간주하여 파라미터나 반환값으로 사용할 수 있으며 참조 투명성을 지킬 수 있다.

함수형 프로그래밍의 특징을 한 줄로 요약하면 위와 같다고 합니다. 모르는 단어들이.. 많아서 하나씩 정리해보겠습니다!

1️⃣ 부수효과 (Side Effect)

  • 변수의 값이 변경된다
  • 자료구조를 제자리에서 수정한다
  • 객체의 필드값을 설정한다
  • 예외나 오류가 발생하며 실행이 중단된다
  • 콘솔 또는 파일 I/O가 발생한다

2️⃣ 순수함수 (Pure Function)

위의 부수효과들을 제거한 함수들을 순수함수(Pure Function)이라고 부르며 함수형 프로그래밍에서 사용하는 함수는 이러한 순수 함수들입니다.

  • Memory 또는 I/O 관점에서 부수효과가 없는 함수
  • 함수의 실행이 외부에 영향을 끼치지 않는 함수

순수함수를 사용하게 되면 다음과 같은 효과를 받을 수 있습니다.

  • 함수 자체가 독립적이며 Side-Effect가 없기 때문에 Thread에 안전성을 보장받을 수 있습니다.
  • Thread에 안정성을 보장받아 병렬 처리를 동기화없이 진행할 수 있습니다.

3️⃣ 1급객체 (First-Class Object)

  • 변수나 데이터 구조 안에 담을 수 있다
  • 파라미터로 전달할 수 있다
  • 반환값으로 사용할 수 있다
  • 할당에 사용된 이름과 무관하게 고유한 구별이 가능하다

함수형 프로그래밍에서 함수는 1급객체로 취급받기 때문에 위의 예제에서 본 것 처럼 함수를 파라미터로 넘기는 등의 작업이 가능한 것입니다.

4️⃣ 참조 투명성 (Referential Transparency)

  • 동일한 인자에 대해 항상 동일한 결과를 반환해야 한다
  • 참조 투명성을 통해 기존의 값은 변경되지 않고 유지된다

명령형 프로그래밍과 함수형 프로그래밍에서 사용하는 함수는 부수효과의 유/무에 따라 차이가 있습니다. 그에 따라 함수가 참조에 투명한지 안한지에 나뉘어 지게 됩니다.

참조에 투명하다는 것은 함수를 실행하여도 어떠한 상태의 변화없이 항상 동일한 결과를 반환해서 항상 동일하게(투명하게) 실행 결과를 참조(예측)할 수 있다는 것을 의미합니다.

간단하게 예시를 들어보자면 어떤 함수 F에 어떤 인자인 x를 넣고 F를 실행하게 되면 F는 입력된 인자에만 의존하기 때문에 항상 F(x)라는 동일한 결과를 얻는다는 의미입니다.

부작용을 제거해서 프로그램의 동작을 이해하고 예측을 용이하게 하는 것은 함수형 프로그래밍으로 개발하려는 핵심 동기 중 하나입니다. 그리고 병렬 처리 환경에서 개발할 때 Race Condition에 대한 비용을 줄여줍니다. 왜냐하면 함수형 프로그래밍에서는 값의 대입이 없이 항상 동일한 실행에 대한 동일한 결과를 반환하기 때문입니다.

저는 이부분이 이해가 안돼서 다른 자료를 참고해서 이해를 어느정도..? 했습니다.

어떤 함수가 input값을 받으면 데이터 처리를 하고나서 새롭게 바뀐 값을 리턴해줍니다. 이 때 input값은 변하지 않습니다. 모든 데이터들을 변경 불가능(Immutable)하게 했기 때문에 여러 쓰레드가 데이터를 건들여도 Race Condition이 거의 없다는 겁니다.


해당 내용은 GitHub에도 올렸으니 궁금하신 분들은 참고해주시면 좋을 것 같습니다 :)

CS스터디 GitHub - 함수형 프로그래밍

추가적으로 예시로 자바스크립트를 기반으로 한 함수형 프로그래밍 예제도 같이 올리려고 했는데 포스팅이 너무 길어져서 참고 링크로 대체하도록 하겠습니다!

Reference

profile
블로그 이전했습니다!! https://dev-iamkanguk.tistory.com/ <<- 여기로 오세용!!

0개의 댓글