함수형 프로그래밍 (Functional Programming)

본 글은 로버트 C.마틴 저자(송준이 엮음)의 [클린 아키텍처: 소프트웨어 구조와 설계의 원칙] 도서를 읽고 작성하였습니다.


6.1. 정의

  • 자료처리를 수학적 함수의 계산으로 취급하고 상태와 가변 데이터를 멀리하는 프로그래밍
  • 함수형 프로그래밍 언어 : 클로저,스칼라,하스켈 등
    • 자바스크립트, 코틀린, 파이썬 등에도 최근 버전에 함수형 프로그래밍 문법이 추가되었음

6.2. 특징

6.2.1. 람다 계산 (Lambda Calculus)

  • 알론조 처치 Alonze Church가 고안한 람다 계산법을 기반으로 함

6.2.2. 순수 함수 (Pure function)

  • 입력 값이 동일하면 결과가 동일하게 리턴되는 수학함수와 동일함
    • 함수의 실행이 프로그램의 실행에 영향을 미치지 않음
    • 함수 내부에서 인자의 값을 변경하거나 프로그램 상태를 변경하는 Side Effect가 없음
  • 계산 절차를 포함하더라도 순수 함수로 만들면 부작용이 없음

    function add(a, b) {
      return a + b;
    }
    
    const result = add(2, 3);
    

6.2.3. 불변성 (Immutable)

  • 람다 계산법의 근간이 되는 개념으로 심볼의 값이 변경되지 않는다는 개념
  • 가변 변수를 사용하는 대신에 심볼에 값을 할당하면 그 값은 변경되지 않음

    • 쉽게 생각해서 데이터의 변경이 필요한 경우 원본 데이터 구조를 변경하지 않고 그 데이터의 복사본을 만들어서 일부를 변경한 후, 변경한 복사본을 사용해 작업을 진행함
    const person = { name: "jongmin", age: "26" };
    
    function increaseAge(person) {
      return { ...person, age: person.age + 1 };
    }
    

6.2.4. 참조투명성과 부작용

  • 프로그램 동작의 변경없이 관련 값을 대체할 수 있다면 표현식을 참조 상 투명하다고 함
    • 참조 상 투명한 함수를 평가하게 되면 동일한 인자에 대해 동일한 값을 반환
  • 순수 함수로 만들면 함수 외부에 값이나 객체를 참조하거나 의존적으로 동작하지 않기 때문에 참조 투명성을 가지고, 부작용이 없음
    • 부작용이 있는 함수는 입력값이 동일해도 함수 외부에 따라서 다른 값이 리턴됨

6.2.5. 람다 혹은 클로저(closure)

  • 클로저는 람다계산식(Lambda Calculus) 구현체
  • 이름 없는 함수(anonymous function)로 리터럴하게 작성 가능
    • 리터럴은 데이터(값) 그 자체를 뜻함
    • 즉, 변수에 넣는 변하지 않는 데이터를 의미
  • 선언된 범위(scope)에서 접근 가능한 변수를 캡처해서 저장하고 닫힘
  • JS 클로저의 경우에는 캡처한 변수를 참조(reference)함

6.3. 1급 객체

  • 함수가 1등 시민(first-class citizen) 혹은 1급 객체

    • 함수를 타입으로 지정할 수 있음
    • 인자값(파라미터)으로 넘길 수 있음
    • 반환값(리턴값)으로 사용할 수 있음
    • 마치 함수도 객체처럼 변수나 함수의 인자, 리터럴하게 다룰 수 있다는 의미
    const addTwo = (num) => num + 2;
    const multiplyTwo = (num) => num * 2;
    const transform = (numbers) => numbers.map(addTwo).map(multiplyTwo);
    
    console.log(transform([1, 2, 3, 4])); // [6, 8, 10, 12]
    

6.4. 고차함수

  • 함수를 더 추상화하면 차원이 높아지는 고차함수로 표현할 수 있음

    • 함수를 인자로써 전달할 수 있어야함
    • 함수를 반환값으로 또 다른 함수를 사용할 수 있음

      const addInform = (name) => (age) => age + name;
      const jongmin = addInform("종민");
      
      console.log(jongmin("96"));
      
  • JS 컬렉션 인터페이스로는 map, filter, reduce가 있음

    • 이러한 인터페이스가 고차함수의 대표적 예시

6.5. 장단점

6.5.1. 장점

  1. 높은 수준의 추상화 제공
  2. 함수 단위의 코드 재사용 수월
  3. 불변성을 지향하기 때문에 프로그램 동작 예측이 수월

6.5.2. 단점

  1. 순수함수를 구현하기 위해서는 코드의 가독성이 떨어질 수 있음
  2. 함수형 프로그래밍에서는 반복이 for문이 아닌 재귀를 통해 이루어지는데(deep copy), 재귀적 코드 스타일은 무한 루프에 빠질 수 있음
  3. 순수함수를 사용하는 것은 쉬울 수 있지만 조합하는 것은 쉽지 않음

Reference

  • 로버트 C.마틴, 2019, 클린 아키텍처: 소프트웨어 구조와 설계의 원칙
  • https://jongminfire.dev/%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%B4%EB%9E%80
  • https://ko.wikipedia.org/wiki/%EC%B0%B8%EC%A1%B0_%ED%88%AC%EB%AA%85%EC%84%B1