ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Endofunctor (엔도펑터), 모나드 (Monad)
    Development/Architecture 2026. 3. 2. 18:36
    반응형

    엔도펑터 (Endofunctor)

     출발하는 카테고리와 도착하는 카테고리가 같은 펑터로, 그리스어 접두사 'Endo-'(내부의)와 의미와 Functor가 결합한 것이다. 프로그래밍에서 다루는 대부분의 펑터가 엔도펑터다. 가장 흔한 예시로 Maybe(or 자바의 Optional)가 있다. (F : C -> C)

     

     엔도펑터 역시 펑터와 마찬가지로 대상 객체를 매핑하는 것 뿐만 아니라 사상 또한 매핑해야 한다. 이를 리프팅(lifting) 한다고 하며, 들어올린다고도 한다.

    ex) a -> b를 Maybe a -> Maybe b 로 리프팅

     

    모나드 (Monad)

     모나드는 엔도펑터 카테고리에서의 모노이드다. 즉, 결합 법칙과 항등 법칙을 만족해야 한다.

    • 펑터는 컨텍스트 안의 값을 바꾸는 함수를 적용한다.
      • map : F<A> -> (A -> B) -> F<B>
      • 함수가 컨텍스트를 생성하지는 않는다.
    • 모나드는 컨텍스트 안의 값에 컨텍스트를 생성하는 함수를 적용한다.
      • flatMap : M<A> -> (A -> M<B>) -> M<B>
      • 함수 자체가 새로운 컨텍스트를 반환한다.
    sealed class Maybe<out A> {
        data class Just<A>(val value: A) : Maybe<A>()
        data object Nothing : Maybe<kotlin.Nothing>()
    
        fun <B> map(f: (A) -> B): Maybe<B> = when (this) {
            is Just -> Just(f(value))
            is Nothing -> Nothing
        }
    
        fun <B> flatMap(f: (A) -> Maybe<B>): Maybe<B> = when (this) {
            is Just -> f(value)
            is Nothing -> Nothing
        }
    }
    
    // ── 순수한 변환: 펑터로 충분
    val number: Maybe<Int> = Maybe.Just(42)
    val doubled: Maybe<Int> = number.map { it * 2 }         // Just(84)
    val asString: Maybe<String> = number.map { it.toString() } // Just("42")
    
    // ── 실패 가능한 연산: 펑터만으로는 한계
    fun safeDivide(a: Int, b: Int): Maybe<Int> =
        if (b != 0) Maybe.Just(a / b) else Maybe.Nothing
    
    val result: Maybe<Maybe<Int>> = number.map { safeDivide(it, 0) }
    // 결과: Just(Nothing) — Maybe가 이중으로 중첩됨.
    // 타입이 Maybe<Maybe<Int>>가 되어버림.
    
    // ── 모나드의 flatMap이 해결
    val clean: Maybe<Int> = number.flatMap { safeDivide(it, 0) }
    // 결과: Nothing — 평탄화됨.

     

    반응형

    댓글

Designed by Tistory.