[FP] 함수의 합성

yongkini ·2024년 10월 29일
0

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
완벽함 보다는 최선의 결과를 위해 끊임없이 노력하는 개발자

0개의 댓글

Powered by GraphCDN, the GraphQL CDN