[FP] 함수의 합성

yongkini ·2024년 10월 29일

Functional Programming

목록 보기
12/21
post-thumbnail

함수의 합성

type PipeFn<T extends any[], R> = (...args: T) => R;

export function pipe<T extends any[], A>(fn1: PipeFn<T, A>): PipeFn<T, A>;
export function pipe<T extends any[], A, B>(fn1: PipeFn<T, A>, fn2: (a: A) => B): PipeFn<T, B>;
export function pipe<T extends any[], A, B, C>(fn1: PipeFn<T, A>, fn2: (a: A) => B, fn3: (b: B) => C): PipeFn<T, C>;
// Add more overloads as needed for additional functions in the pipeline

export function pipe(...fns: Function[]) {
  return (...args: any[]) => fns.reduce((result, fn) => [fn(...result)], args)[0];
}

export const asyncPipe =
  (...fns: ((value: any) => any)[]) =>
  (initialValue: any) =>
    fns.reduce((promise, fn) => promise.then(fn), Promise.resolve(initialValue));

위의 pipe 툴을 이용해서 함수들을 합성해본다. compose와 달리 pipe는 나의 직관과 일치하는데, 앞에서부터 차례로 실행하고, return 값을 뒤의 함수의 매개변수에 넣는다. 여기에서 좀 더 간결한 로직을 만들 수 있도록 앞에서 튜플 등의 자료구조를 배웠던 것이다 혹은 커리나, 부분 적용으로 더 쉽게 만들 수 있다. 어쨌든, 위의 pipe를 써서 직접 만들어본 로직은 이거였다. 하지만, 이건 위의 로직을 써보기 위해 좀 억지스럽게 만든 느낌이 좀 들긴한다.

const checkURLParams = ([type, id]: string[]) => {
  if (type === ':type' || !type) {
    return { action: 'redirect', route: 'home' };
  } else if (id === ':id' || !id) {
    return { action: 'redirect', route: 'template-list', params: { type } };
  } else {
    return { action: 'proceed', id };
  }
};

const handleRouting = async (result: ReturnType<typeof checkURLParams>) => {
  if (result.action === 'redirect') {
    await router.push({
      name: result.route,
      ...(result.params && { params: result.params }),
    });
  }
  return result.id || ''; 
};

const initAPI = async (id: string) => {
  try {
    if (isValid(id)) {
      const response = await template.getTemplate(id);
      return response;
    }
  } catch (err) {
    await router.push({ name: 'template-list' });
  }
};

const initComponent = asyncPipe(checkURLParams, handleRouting, initAPI);

: 사실 위의 로직이 꼭 함수형으로 작성됐어야 하는건 아니고, 저 코드가 그렇게 깔끔해 보이지도 않는다. 요즘 뭔가 함수형 프로그래밍에 대해 배우고 나서 이걸 꼭 적용해야겠다라는 강박이 있어서 그런지 좀 안어울리는 코드가 양산(?)되고 있는 느낌도 있다. 그리고 아직 함수형에 적응을 제대로 못한 것도 맞는 것 같다. 따라서, 이제부터는 일단 프로젝트를 진행할 때는

  • 순수 함수(Pure Function)로 모든 함수를 작성하고, 그 쪼개진 순수 함수를 조립해서 로직을 작성한다.

위의 규칙만을 일단은 고려하면서 개발해보자. pipe, curry, partial, Either 등 배운 것을 써먹으려는 시도도 좋지만, 일단 함수형 프로그래밍의 기본인 부수효과가 없는 순수 함수들의 조합을 통한 관심사 분리 및 재사용성 증대의 측면에서 접근해보자. 그러면서 자연스럽게 위의 도구들이 생각나서 쓰도록 해보자. 모든 함수를 아토믹 패턴에서 atom의 정도로 쪼개서 쓰면서 역시 아토믹 패턴처럼 그 함수들을 조합해서 새로운 함수를 계속해서 생성하면서 써나간다 라는 것에 초점을 맞춰보자.

profile
Web3.0에 관심이 많은 FE 개발자입니다. VPA와 캔들 차트 분석을 기반으로 정량적 트레이딩 시스템을 직접 개발하여 암호화폐를 트레이딩하고 있습니다.

0개의 댓글