# TypeScript로 이해하는 펑터, 어플리케이티브 펑터, 모나드

> Clean Markdown view of GeekNews topic #26500. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=26500](https://news.hada.io/topic?id=26500)
- GeekNews Markdown: [https://news.hada.io/topic/26500.md](https://news.hada.io/topic/26500.md)
- Type: news
- Author: [bboydart91](https://news.hada.io/@bboydart91)
- Published: 2026-02-08T12:00:06+09:00
- Updated: 2026-02-08T12:00:06+09:00
- Original source: [evan-moon.github.io](https://evan-moon.github.io/2026/02/07/monads-in-typescript/)
- Points: 9
- Comments: 2

## Summary

펑터의 **map 한계**에서 출발해 어플리케이티브 펑터와 모나드로 확장되는 과정을 TypeScript 코드로 풀어냅니다. 컨테이너 안에 갇힌 함수 적용 문제와 맥락 중첩을 해결하기 위해 `apply`, `join`, `flatMap`이 어떻게 등장했는지를 단계적으로 보여주며, 모나드가 “내부함자 범주의 모노이드 대상”으로 불리는 이유를 수학적 대응 관계로 설명합니다. Promise가 실무적으로는 모나딕하게 동작하지만, 엄밀한 의미의 모나드가 아닌 이유도 함께 짚습니다.

## Topic Body

본문  
  
  - 펑터의 map만으로는 해결할 수 없는 두 가지 문제(컨테이너 안 함수가 갇히는 문제, 합성 시 맥락 중첩 문제)에서 출발하여 어플리케이티브 펑터와 모나드까지 도달하는 과정을 TypeScript 코드로 설명  
  - 1988년 에우제니오 모지(Eugenio Moggi)가 프로그램을 A → B가 아닌 A → T(B)로 모델링한 배경에서 시작  
  - flatMap = map + join이라는 구조와, 이를 안전하게 사용하기 위한 세 가지 법칙(결합, 좌단위, 우단위)을 다룸  
  - 모나드가 왜 **"내부함자 범주의 모노이드 대상"** 인지를 정수 덧셈의 모노이드에 대비하여 설명  
  - Promise는 모나딕하게 작동하지만 엄밀한 수학적 모나드는 아닌 이유도 언급  
  
  펑터의 한계: map으로 안 되는 것들  
  
  - 커링된 함수를 map으로 적용하면 결과가 Maybe<(b: number) => number>처럼 함수가 컨테이너 안에 갇힘  
    - map은 컨테이너 바깥의 함수만 받을 수 있어서, 안에 갇힌 함수를 다른 값에 적용할 방법이 없음  
  - 펑터를 반환하는 두 함수를 합성하면 Maybe&lt;Maybe&gt;처럼 맥락이 중첩됨  
    - 단계가 늘어날수록 Maybe<Maybe<Maybe<...>>>로 무한 중첩  
  
  어플리케이티브 펑터: 컨테이너 안의 함수 적용  
  
  - apply 연산으로 컨테이너 안에 갇힌 함수를 다른 컨테이너의 값에 적용 가능  
    - apply: T<(A → B)> → T&lt;A&gt; → T&lt;B&gt;  
  - pure 연산으로 순수 값을 컨테이너에 삽입  
  - 한계: 어떤 컨테이너들을 합성할지 미리 정해져 있어야 함  
    - 이전 계산 결과를 보고 다음 계산을 결정하는 동적 순차 의존성을 표현할 수 없음  
  
  모나드: 중첩을 펴는 연산의 발명  
  
  - join 연산이 T<T&lt;A&gt;> → T&lt;A&gt;로 이중 컨테이너를 단일로 펴줌  
    - JavaScript의 Array.prototype.flat이 같은 역할  
  - 실무에서는 map + join을 합친 flatMap을 사용  
    - flatMap: T&lt;A&gt; → (A → T&lt;B&gt;) → T&lt;B&gt;  
    - map은 A → B를 받지만 flatMap은 A → T&lt;B&gt;를 받아서 결과를 한 겹으로 유지  
  
  flatMap의 세 가지 법칙  
  
  - 결합 법칙: 삼중 중첩 T(T(T(A)))를 펼 때 안쪽부터 펴든  
  바깥부터 펴든 결과가 동일해야 함  
    - m.flatMap(f).flatMap(g) === m.flatMap(x =>  
  f(x).flatMap(g))  
  - 좌단위 법칙: pure로 넣었다가 바로 flatMap하면 그냥 함수를 직접 적용한 것과 동일  
    - pure(a).flatMap(f) === f(a)  
  - 우단위 법칙: flatMap에 pure를 넘기면 원래 컨테이너 그대로  
    - m.flatMap(pure) === m  
  
  "내부함자 범주의 모노이드 대상" 분해  
  
  - 프로그래밍의 펑터는 타입 세계에서 타입 세계로 향하므로 엔도펑터(내부함자)  
  - 엔도펑터들 자체를 대상으로 놓는 엔도펑터 카테고리를 구성할 수 있음  
  - 모노이드의 요건(이항 연산 + 결합 법칙 + 항등원)에 대입하면:  
    - 이항 연산 = join  
    - 항등원 = pure  
    - 정수 덧셈의 모노이드와 구조가 정확히 대응됨  
  
  Promise는 모나드가 아닌 이유  
  
  - then이 map과 flatMap을 반환값에 따라 섞어서 처리함  
  - Promise&lt;Promise&gt; 상태가 런타임에서 허용되지 않고 즉시 단일  
  계층으로 합쳐짐  
  - 실무적으로 편리하지만 수학적 모나드 법칙을 만족하지 않음

## Comments



### Comment 50824

- Author: calofmijuck
- Created: 2026-02-08T15:05:16+09:00
- Points: 1

Comonad도 다뤄주세요!

### Comment 50909

- Author: bboydart91
- Created: 2026-02-09T21:21:19+09:00
- Points: 1
- Parent comment: 50824
- Depth: 1

으아...고민해보겠습니다 ㅋㅋㅋㅋ
