Footnotes

  1. Jotai 의 atom((get) => …) 이 async/await 와 같은 모양인 건 우연이 아니다 — atom 과 Promise 가 둘 다 모나드라 같은 do-notation 을 쓴다. 모나드는 of·map·join 셋을 구현할 수 있는 구조. ↩

  2. 타입·범주론 없이 모나드를 “발명”해 보는 글. null 체크 조건문을 없애려고 whenExists 체이너를 만들다가, 체이너를 돌려주는 함수끼리 이으려니 중첩이 생기고 그걸 펴는 과정에서 모나드가 나온다. ↩

  3. 2013년 콜백 지옥에서 출발해 Promise·배열의 공통 패턴을 뽑아 Functor → Monad 로 가는 TypeScript 글. async/await 가 모나드 위에 지은 문법이라는 데까지 간다(보너스로 Monoid). ↩

  4. Studying With Alex 채널의 모나드 입문 영상. ↩

  5. pipe(x, a, b) 를 2,560번 쓴 회고. b(a(x)) 를 왼쪽에서 오른쪽으로 읽게 하는 함수(reduce 한 줄)이고, 함수를 합성만 하는 compose 보다 고차 함수로 생각할 필요가 없어 읽기 쉽다 — 메서드 체이닝을 네이티브 메서드 밖으로 넓힌 것. ↩

  6. 파이프 연산자 |> 제안에 4년 관여한 저자가 F# 파이프 지지에서 Hack 파이프(플레이스홀더)로 돌아선 이유. Hack 파이프가 커링 없이도 쓸 수 있어 함수형 라이브러리와 일반 JS 사이를 잇는다는 주장. ↩

  7. pipe 는 함수 n 개를 왼쪽→오른쪽으로, compose 는 오른쪽→왼쪽으로 잇는다는 입문 (freeCodeCamp 로 옮겨진 글). ↩

  8. 고차 함수 입문. 함수가 값(일급 시민)이라 인자로 넘기고 돌려줄 수 있고, 그게 DOM 조작 같은 실무 코드에서 왜 쓸모 있는지 예제로 보인다. ↩

#215
/**
 * - 인자 수 확인: `curry` 함수는 전달된 함수 `fn`의 인자 수를 확인
 * - 인자 수가 충분한 경우: 만약 `args`의 길이가 `fn`의 인자 수 이상이면, `fn`을 호출하고 결과를 반환
 * - 인자 수가 부족한 경우: 그렇지 않으면 추가 인자(`moreArgs`)를 받을 수 있는 새 함수를 반환. 이 함수는 기존 인자(`args`)와 새로운 인자(`moreArgs`)를 합쳐 다시 `curry(fn)`을 호출하여 최종적으로 인자가 충분할 때까지 이 과정을 반복
 */
const curry =
  (fn: Function) =>
  (...args: any[]) =>
    args.length >= fn.length
      ? fn(...args)
      : (...moreArgs: any[]) => curry(fn)(...args, ...moreArgs)

/**
 * - `...fns: Function[]` 여러 개의 함수를 인자로 받는다
 * - 내부에서 `reduce` 메서드를 사용하여 함수 배열을 순회 초기값으로 `x`를 사용하며, 각 함수 `fn`을 차례로 호출하여 결과를 다음 함수로 전달
 */
const pipe =
  (...fns: Function[]) =>
  (x: any) =>
    fns.reduce((acc, fn) => fn(acc), x)

/**
 * - `...fns`: 여러 개의 함수를 매개변수로 받음
 * - `(x)`: 초기값 `x`를 인자로 받아 결과를 리턴
 * - `fns.reduceRight(...)`: 배열의 오른쪽부터 왼쪽으로 각 함수를 적용합니다. `y`는 이전 함수의 결과이며, `f`는 현재 함수
 * - `f(y)`: 현재 함수 `f`를 이전 함수의 결과 `y`에 적용
 */
const compose =
  (...fns) =>
  (x) =>
    fns.reduceRight((y, f) => f(y), x)

  1. 함수 조합(Composition): 작은 함수들을 조합하여 새로운 함수를 만들며, 예를 들어 compose(f, g, h)는 f(g(h(x)))로 실행
  2. compose: 오른쪽에서 왼쪽으로 함수를 실행하며, compose(square, double)(3)은 36을 반환
  3. pipe: 왼쪽에서 오른쪽으로 함수를 실행하여, pipe(double, square)(3)의 결과는 36
  4. 커링(Currying): f(a, b, c)를 f(a)(b)(c) 형태로 변환하고, 예를 들어 add(1)(2)(3)의 결과는 61
  5. 부분 적용(Partial Application): 일부 인자만 미리 적용하여 새로운 함수를 만들 수 있으며, const double = multiply(2, _)로 정의
  6. 포인트-프리 스타일: 변수를 사용하지 않고 함수를 조합하여 작성하며, 예를 들면 compose(square, double)와 같은 형태
  7. 데이터 마지막 원칙(Data Last): 데이터를 마지막 인자로 배치하여 조합성을 높이는데, 예를 들어 const halve = divideDataLast(2)와 같이 사용

Footnotes

  1. Function: length - MDN: “The length data property of a Function instance indicates the number of parameters expected by the function.” ↩

#385