함수형 프로그래밍

함수형 프로그래밍 이란?

  • 자료 처리를 수학적 함수의 계산으로 취급하고 상태와 가변 데이터를 멀리하는 프로그래밍 패러다임의 하나이다

  • 함수를 값처럼 여기며 순수 함수(pure function)를 조합하고 가변 데이터(mutable data) 및 부작용(side-effects) 을 피하는 프로그래밍 패러다임이다.

함수형 프로그래밍 규칙

  • 모든 데이터는 변경이 불가능(Immutable) 해야한다.

  • 모든 함수는 순수 함수이여야 한다.

  • 루프보다는 재귀를 사용한다.

1급 객체

다음과 같은 조건을 만족하는 객체

  • 변수나 데이터 구조안에 담을 수 있다.

  • 파라미터로 전달 할 수 있다.

  • 반환값(return value)으로 사용할 수 있다.

  • 할당에 사용된 이름과 관계없이 고유한 구별이 가능하다.

  • 동적으로 프로퍼티 할당이 가능하다.

Javascript에서 함수는 1급 객체이다.

불변성

  • 함수형 프로그래밍에서는 데이터가 변할 수 없다

  • 데이터 변경이 필요한 경우, 원본 데이터 구조를 변경하지 않고 그 데이터를 복사본을 만들어 그 일부를 변경하고, 변경한 복사본을 return 한다

// Mutatable
function updateRanking({user, ranking}) {
  user.ranking = ranking;
  return user;
}
const smith = { ranking: 10, name: "smith" };
updateRanking({user: smith, ranking: 5});
console.log(smith.ranking); // 5

// Immutable
function updateRanking({user, ranking}) {
  return { ...user, ranking };
}
const myProfile = { ranking: 2, name: "john" };
const newProfile = updateRanking({user: john});
console.log(john.ranking); // 2 변하지 않음
console.log(changedJohn.ranking); // 1

순수 함수

  • 동일한 입력에는 항상 같은 값을 반환해야 한다.

  • 함수의 실행은 프로그램의 실행에 영향(외부 변수 수정, 삭제, 추가 등...)을 미치지 않아야 한다. (Side effect 가 없어야 한다)

// 비 순수함수(c의 값에 따라 다른 값이 반환됨)
function sum(a, b) {
  return a + b + c;
}
// 비 순수함수(sum이라는 외부 변수의 값을 수정함)
function sum2(a, b) {
  sum = a + b;
  return a + b;
}

// 순수함수
function sum3(a, b) {
  return a + b;
}

고차 함수

  • 함수에 함수를 파라미터로 전달하는 함수

  • 반환값으로 함수를 반환하는 함수

Array.prototype의 map, filter, forEach등 다 고차 함수이다.

커링(currying)

  • 커링이란 여러개의 파라미터를 가진 함수를 호출 할 경우, 파라미터의 수보다 적은 수의 파라미터를 인자로 받으면 누락된 파라미터를 다음 파라미터로 받는 기법

function sum(a, b) {
  return a + b;
}

// bind를 사용한 currying
const addOne = sum.bind(null, 1);
console.log(addOne(10)); // 11

// 직접 커링 구현
function curry(fn, ...args) {
  // 첫번째 인자가 함수가 아닐때
  if (typeof fn !== "function") {
    console.error("첫번째 인자로 함수를 넣어주세요");
    return;
  }
  // 2번째 이후 인자로 받은 인자수가 첫번째 인자로 받은 함수의 인자수보다 크거나 같을때
  if (args.length >= fn.length) {
    return fn(...args);
  }
  // 2번째 이후 인자로 받은 인자수가 첫번째 인자로 받은 함수의 인자수보다 적을때 재귀호출
  return (...more) => curry(fn, ...args, ...more);
}
const addOne2 = curry(sum, 1);
console.log(addOne2(1)); // 2

합성 함수

  • 합성 함수란 새로운 함수를 만들거나 계산하기 위해 둘 이상의 함수를 조합하는 과정을 말한다. 함수형 프로그래밍은 함수를 값으로 여길수 있기 때문에 함수들을 연쇄적으로 호출하여 더 큰 함수를 만들수 있다.

function curry(func, ...args) {
  return func.bind(null, ...args);
}

function sum(a, b) {
  return a + b;
}
const addTwo = curry(sum, 2);
console.log(addTwo(sum(2, 6))); // 10

펑터(functor)

  • 펑터는 Mappable (Mapping 함수를 갖는)한 데이터 구조이다.

  • 컬렉션의 각 원소에 대해 매핑((a: T) => U) 함수를 적용해서 T 타입의 원소들을 U 타입으로 변경시킬 수 있으면 펑터로 부를 수 있다.

  • JavaScript의 Array는 Array.map 메소드를 갖고있기 때문에 펑터이다.

모나드(Monad)

  • 모나드는 순서가 있는 연산을 처리하는데 사용하는 디자인 패턴이다.

  • 타입 M에 대해 세 가지 용도의 함수 fmap(mapping 함수), pure(A 타입을 M<A>로 만드는 함수), join(M<M<A>> 타입을 M<A>로 만드는 함수)을 만들 수 있을 때, 타입 M은 모나드이다.

  • 비동기 연산 처리(Continuation 모나드)나 null 처리(Maybe 모나드)를 같은 것을 해야하는 상황에서 함수를 안전하게 합성 하기위해 모나드를 사용할 수 있다.

  • JavaScript의 Promise는 비동기 상황에서 함수를 안전하게 합성하게 해주는 모나드이다

  • 또한 Promise는 Kleisli Composition(오류가 있을수 있는 상황에서 함수 합성을 안전하게 하는 규칙) 이기도 한다.

함수형 프로그래밍의 장점

모듈성과 재사용성을 높인다

한가지의 역할만 하는 함수들을 조합해 로직을 구성하기 때문에 중복되는 로직을 추가 해야할 때 미리 만들어 놓은 함수를 사용하면 된다.

테스트 하기 쉽다

함수형 프로그래밍에서 함수는 순수 함수이기 때문에 외부 환경에 신경을 안쓰고 오직 함수 내부 로직에만 집중을 하면 되므로 테스트 하기가 수월하다

객체지향 프로그래밍과 비교한 함수형 프로그래밍의 장점

함수형 프로그래밍은 동일한 입력이 들어왔을경우 똑같은 값이 반환되어 예측가능하지만(순수 함수) 객체지향 프로그래밍은 동일한 입력이 들어왔을경우 클래스의 필드 값에따라 다른 값이 반환될수있어 예측이 불가능하다.

Last updated