Monad์™€ Functor ์‚ฌ์ด์—๋Š” Monoidal Functor๋ผ๋Š” ์ค‘๊ฐ„ ๋‹จ๊ณ„๊ฐ€ ์žˆ๋‹ค.

Monoidal Functor๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋Š” ์–ธ์–ด

์•„๋ฌด ์–ธ์–ด์—์„œ๋‚˜ ์ •์˜๋  ์ˆ˜ ์žˆ๋Š” ๊ฐœ๋…์€ ์•„๋‹ˆ๋‹ค. ๋‹ค์Œ์˜ ์กฐ๊ฑด์ด ์„ ํ–‰๋˜์–ด์•ผ ํ•œ๋‹ค.

  1. Empty Type ์„ ์ œ๊ณตํ•ด์•ผ ํ•œ๋‹ค.
    • Void
    • ()
    • C์—์„œ ๋นˆ ๊ตฌ์กฐ์ฒด ๋“ฑ
  2. T, U ํƒ€์ž…์— ๋Œ€ํ•œ Pair๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ํŠœํ”Œ ํƒ€์ž… ๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•œ๋‹ค.
  3. ํŠœํ”Œ ํƒ€์ž…๊ณผ ๋นˆ ํƒ€์ž…์€ ๋‹ค์Œ์˜ ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•œ๋‹ค.
    • empty: - ๋นˆ ํŠœํ”Œ์„ ๋งŒ๋“ค์–ด์คŒ
    • unite: - ๋‘ ๊ฐ’์„ ํŠœํ”Œ๋กœ ๋ฌถ์–ด์คŒ
    • e1:
    • e2:

์ฆ‰, ๋‹ค์Œ์„ ๋งŒ์กฑํ•ด์•ผ ํ•œ๋‹ค.

unite(e1(u), e2(u)) = u

internal func empty() -> Void {
    ()
}
 
internal func unite<T, U>(_ t: T, _ u: U) -> (T, U) {
    (t, u)
}
 
internal func e1<T, U>(_ tu: (T, U)) -> T {
    tu.0
}
 
internal func e2<T, U>(_ tu: (T, U)) -> U {
    tu.1
}

unite ํŒŒ์ƒํ•จ์ˆ˜๋“ค

n๊ฐœ์˜ ๊ฐ’์„ n๊ฐœ๊ฐ€ ํ•˜๋‚˜์˜ ํƒ€์ž…์•ˆ์— ๋“ค์–ด๊ฐ€๋„๋ก ํ•˜๋Š” unite_n์„ ์•Œ์•„๋ณด์ž. ์ฆ‰, n๊ฐœ ์ธ์ˆ˜๋ฅผ ํ•˜๋‚˜์˜ ์ธ์ˆ˜๋กœ ๋ฐ”๊ฟ”์ค€๋‹ค.

  • unite_0 = empty
  • unite_1 = identity
  • unite_{n}(t1, ..., tn) = unite(unite_{n-1}(t1, ..., t{n-1}), t{n})
unite3(t1, t2, t3)
= unite1(unite2(t1, t2), t3)
= unite1(unite1(unite1(t1), unite1(t2)), unite1(t3))
  • ํ•˜์ง€๋งŒ ์ด ํ•จ์ˆ˜๋Š” ์™„์ „ ๊ตฌํ˜„์ด swift๋กœ ๋ถˆ๊ฐ€ํ•˜๋‹ค.
  • tuple์ด๋ผ๋Š” ์ž๋ฃŒ๊ตฌ์กฐ์˜ ์ธ์ž ๊ฐœ์ˆ˜๋ฅผ ๋ถˆํŠน์ •ํ•œ ์ƒํƒœ๋กœ ์„ ์–ธํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
  • ๊ตณ์ด ๊ตฌํ˜„ํ•ด๋ณธ๋‹ค๋ฉด ์ด๋Ÿฐ ํ˜•ํƒœ๊ฐ€ ๋˜๊ฒ ๋‹ค.
internal func unite0() -> Void {
    empty()
}
 
internal func unite1<T>(_ t: T) -> T {
    identity(t)
}
 
internal func unite2<T, U>(_ t: T, _ u: U) -> (T, U) {
    (t, u)
}
 
internal func unite3<T1, T2, T3>(_ t1: T1, _ t2: T2, _ t3: T3) -> ((T1, T2), T3) {
    unite2(unite2(t1, t2), t3)
}
 
internal func unite4<T1, T2, T3, T4>(_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4) -> (((T1, T2), T3), T4) {
    unite2(unite3(t1, t2, t3), t4)
}

unite_arg

  • ๊ทธ๋Ÿผ ์ด์™€ ๊ฐ™์€ ํ˜•ํƒœ์˜ ํ•จ์ˆ˜๋„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„๊นŒ?
unite_arg_3
: ((T1, T2, T3) -> U) -> (((T1, T2), T3) -> U)
internal func uniteArg3<T1, T2, T3, U>(_ f: @escaping ((T1, T2, T3) -> U)) -> (((T1, T2), T3)) -> U {
    { t12_3  in
        f(e1(e1(t12_3)), e2(e1(t12_3)), e2(t12_3))
    }
}

์ฃผ์–ด์ง„ ํ•จ์ˆ˜๋งŒ์œผ๋กœ ๊ฐ€๋Šฅํ•˜๋‹ค.

reassociate_r

reassociate_r
: ((T, U), V) -> (T, (U, V))
func reassociateR(tl: ((T, U), V))) -> (T, (U, V)) {
	unite(e1(e1(tl)), unite(e2(e1(tl)), e2(tl)))
}

reassociate_l

reassociate_l
: (T, (U, V)) -> ((T, U), V)
func reassociateL(tr: (T, (U, V))) -> ((T, U), V) {
	unite(unite(e1(tr), e2(e1(tr))), e2(e2(tr)))
}

Monoidal Functor ์ •์˜

๋‹ค์Œ์„ ๋งŒ์กฑํ•˜๋Š” Functor M์„ Monoidal Functor๋ผ ํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ M์€ Monoidal Functor๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

  • pure: T -> M<T>
  • gather: Tuple(M<T>, M<U>) -> M<Tuple(T, U)>

์ฆ‰, Functor ์ค‘์—์„œ, lift๊ฐ€ ์žˆ๋Š” 33. Generic์ค‘์— ๊ฐ’์„ 33. Generic์œผ๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์œผ๋ฉด์„œ

33. Generic์˜ ํŠœํ”Œ์„ ํŠœํ”Œ์˜ 33. Generic์œผ๋กœ ๋งŒ๋“ค์–ด์ค„ ์ˆ˜ ์žˆ๋Š” ๋…€์„์„ ๋งํ•œ๋‹ค. Optional์„ ์˜ˆ๋กœ ์ฝ”๋“œ๋ฅผ ์ฒจ๋ถ€ํ•ด๋ณธ๋‹ค.

internal func pure<T>(_ value: T) -> Optional<T> {
	Optional(value)
}
 
internal func gather<T, U>(_ tuple: (Optional<T>, Optional<U>)) -> Optional<(T, U)> {
    switch tuple {
    case (.some(let t), .some(let u)):
        return Optional((t, u))
    default:
        return nil
    }
}

Monoidal Functor์˜ ์กฐ๊ฑด

Conservation of associativity

Conservation of identity element

Monoidal Functor์˜ ๋ชฉ์ 

๋‹ค์ธ์ˆ˜ ํ•จ์ˆ˜์˜ ์ž์—ฐ์Šค๋Ÿฌ์šด lift๋ฅผ ์œ„ํ•จ

  • ๊ทธ๋Ÿฐ๋ฐ ์•ž์—์„œ functor๋งŒ ๊ฐ€์ง€๊ณ ๋„ ๋‹ค์ธ์ˆ˜ ํ•จ์ˆ˜์˜ lift๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ์ง€ ์•Š์•˜๋‚˜?
  • lift2d: ((T, U) -> V) -> ((F<T>, F<U>) -> F<F<V>>)
  • ํ•˜์ง€๋งŒ ์ธ์ˆ˜ ๋ฐ˜ํ™˜ ํƒ€์ž…์— Generic์ด ์ธ์ˆ˜ ๊ฐœ์ˆ˜๋งŒํผ ๋“ค์–ด๊ฐ€์„œ ๋‚˜์˜จ๋‹ค.
  • lift2: ((T, U) -> V) -> ((M<T>, M<U>) -> M<M<V>>)
  • ์šฐ๋ฆฐ ์œ„์™€ ๊ฐ™์€ ํ˜•ํƒœ๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ์€ ๊ฒƒ์ด๋‹ค.
  • ํ˜น์€
  • lift0: (() -> U) -> (() -> M<U>)
  • ์ด๋Ÿฐ ํ˜•ํƒœ๋„ ์ •์˜ํ•ด์„œ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค.
  • ์ด๋Ÿฐ ์กฐ๊ฑด์„ ์š”๊ตฌํ•˜๋‹ค๋ณด๋‹ˆ ๋‚˜์˜จ๊ฒŒ Monoidal Functor์ด๋‹ค.
  • Monoidal Functor๊ฐ€ ์–ด๋–ป๊ฒŒ ๋‹ค์ธ์ˆ˜ ํ•จ์ˆ˜์˜ lift๋ฅผ ์›ํ•˜๋Š”๋Œ€๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณด์ž.

m_unite_{n}

n๊ฐœ์˜ Monoidal functor๋ฅผ ํŠœํ”Œ์˜ ๊ฐ’์œผ๋กœ ๊ฐ€์ง€๋Š” ํŠœํ”Œ์„ ํ•˜๋‚˜์˜ Monoidal Functor๋กœ ๋งŒ๋“œ๋Š” ํ•จ์ˆ˜

m_unite_{n}
(M<T1>, ..., M<T{n}>) -> M<(((T1, T2), T3), ..., T{n})>

m_unite_0 = pure(()) : (() -> M<T>)
m_unite_1(m1) = m1 : (M<T> -> M<T>)
m_unite_n(m1, ..., m{n}) = gather(unite(m_unite_{n-1}(m1, ..., m{n-1}), m{n}))
: (M<T1>, ..., M<T{n}>) -> M<(((T1, T2), T3), ..., T{n})>
  • ์œ„์™€ ๊ฐ™์ด ์žฌ๊ท€์ ์œผ๋กœ ์ •์˜ํ•˜๋ฉด ๋œ๋‹ค.
  • ์ด๋ฅผ ํ•จ์ˆ˜๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ์€ ์–ด๋ ต์ง€ ์•Š๋‹ค.
internal func mUnite0() -> Optional<Void> {
    pure(empty())
}
 
internal func mUnite1<T>(_ mt: Optional<T>) -> Optional<T> {
    identity(mt)
}
 
internal func mUnite2<T1, T2>(_ mt1: Optional<T1>,
                             _ mt2: Optional<T2>) -> Optional<(T1, T2)> {
    gather(unite(mt1, mt2))
}
 
internal func mUnite3<T1, T2, T3>(_ mt1: Optional<T1>,
                                  _ mt2: Optional<T2>,
                                  _ mt3: Optional<T3>) -> Optional<((T1, T2), T3)> {
    mUnite2(mUnite2(mt1, mt2), mt3)
}
 
internal func mUnite4<T1, T2, T3, T4>(_ mt1: Optional<T1>,
                                      _ mt2: Optional<T2>,
                                      _ mt3: Optional<T3>,
                                      _ mt4: Optional<T4>) -> Optional<(((T1, T2), T3), T4)> {
    mUnite2(mUnite3(mt1, mt2, mt3), mt4)
    // == mUnite2(mUnite2(mUnite2(mt1, mt2), mt3), mt4)
}

์ฆ‰, ์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๊ฐ€ ํ•œ ์ผ์€ ์—ฐ๋‹ฌ์•„ ๋‚˜์˜จ n๊ฐœ์˜ ๊ฐ’์„ nestedํ•œ ํ•˜๋‚˜์˜ ํŠœํ”Œ๋กœ ๋ฌถ์€ ๊ฒƒ์ด๋‹ค.

lift_n

  • ๊ทธ๋Ÿผ m_unite_n์„ ๊ฐ€์ง€๊ณ  lift_n์„ ๋งŒ๋“ค์–ด๋ณด์ž.
lift_n
: ((T1, ..., T{n}) -> U) -> (M<T1>, ..., M<T{n}) -> M<U>
internal func lift3<T1, T2, T3, U>(_ f: @escaping ((T1, T2, T3) -> U)) -> (T1?, T2?, T3?) -> U? {
    { mt1, mt2, mt3 in
        lift(uniteArg3(f))(mUnite3(mt1, mt2, mt3))
    }
}
  • ์žฌ๋ฐŒ๋Š” ๊ฑด lift_n์„ ๊ฐ€์ง€๊ณ  m_unite_n๋„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
internal func lift3<T1, T2, T3, U>(_ f: @escaping ((T1, T2, T3) -> U)) -> (T1?, T2?, T3?) -> U? {
    { mt1, mt2, mt3 in
        lift(uniteArg3(f))(mUnite3(mt1, mt2, mt3))
    }
}
 
internal func unite3<T1, T2, T3>(_ t1: T1, 
								 _ t2: T2, 
								 _ t3: T3) -> ((T1, T2), T3) {
    unite(unite(t1, t2), t3)
}
 
internal func mUnite3<T1, T2, T3>(_ mt1: T1?,
                                  _ mt2: T2?,
                                  _ mt3: T3?) -> ((T1, T2), T3)? {
    mUnite2(mUnite2(mt1, mt2), mt3)
}
 
internal func mUnite3<T1, T2, T3>(_ mt1: T1?,
                                  _ mt2: T2?,
                                  _ mt3: T3?) -> ((T1, T2), T3)? {
    lift3(unite3)(mt1, mt2, mt3)
}

mUnite3 = lift3(unite3)

  • ์ด ์–˜๊ธฐ๋Š” mUnite_n๊ณผ lift_n์ด ์„œ๋กœ๋ฅผ ํ†ตํ•ด ์ •์˜ํ•  ์ˆ˜ ์žˆ๋Š” ๋™์น˜ ๊ด€๊ณ„์— ์žˆ์Œ์„ ์˜๋ฏธํ•œ๋‹ค.

pure์™€ gather

  • pure์™€ gather ์—ญ์‹œ lift๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ •์˜ ๊ฐ€๋Šฅํ•˜๋‹ค.
internal func pure<T>(_ value: T) -> Optional<T> {
    Optional(value)
}
 
internal func pureFromLift<T>(_ value: T) -> Optional<T> {
    lift0 { () -> T in
        value
    }()
}
internal func gather<T, U>(_ tuple: (Optional<T>, Optional<U>)) -> Optional<(T, U)> {
    switch tuple {
    case (.some(let t), .some(let u)):
        return Optional((t, u))
    default:
        return nil
    }
}
 
internal func gatherFromLift<T, U>(_ tuple: (Optional<T>, Optional<U>)) -> Optional<(T, U)> {
    mUnite2(e1(tuple), e2(tuple))
}

์ •๋ฆฌํ•ด๋ณด์ž.

  • ์•„๋ž˜ 4๊ฐœ์˜ ํ•จ์ˆ˜๊ฐ€ ๋™์ž‘ํ•˜๋Š” ์–ธ์–ด์—ฌ์•ผ Monoidal Functor๋Š” ์ •์˜๋œ๋‹ค.
enum Summary {
 
}
 
extension Summary {
 
    internal func empty() -> Void {
        ()
    }
 
    internal func unite<T, U>(_ t: T, _ u: U) -> (T, U) {
        (t, u)
    }
 
    internal func e1<T, U>(_ tu: (T, U)) -> T {
        tu.0
    }
 
    internal func e2<T, U>(_ tu: (T, U)) -> U {
        tu.1
    }
 
}

Monoidal Functor๊ฐ€ ๋˜๊ธฐ ์œ„ํ•œ ์กฐ๊ฑด, ์•„๋ž˜์˜ ๋‘ ํ•จ์ˆ˜๋งŒ ์ •์˜๋˜๋ฉด ๋œ๋‹ค.

extension Summary {
 
 
 
    internal func pure<T>(_ t: T) -> T? {
        Optional(t)
    }
 
    internal func gather<T, U>(_ tuple: (T?, U?)) -> (T, U)? {
        switch tuple {
        case (.some(let t), .some(let u)):
            return Optional((t, u))
        default:
            return nil
        }
    }
 
}
  • ์ด์ƒํ™ฉ์—์„œ ์šฐ๋ฆฌ๊ฐ€ ํ•˜๊ณ  ์‹ถ์€๊ฒŒ ๋ญ˜๊นŒ?
  • ์šฐ๋ฆฌ๊ฐ€ ํ•˜๊ณ  ์‹ถ์€ ๊ฑด ๋‹ค์ธ์ˆ˜ ํ•จ์ˆ˜์˜ lift๋ฅผ ์ž˜ ์ •์˜ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
  • ((T1, T2, T3) โ†’ U)) โ†’ (T1?, T2?, T3?) โ†’ U? ์ด๋Ÿฐ ํ˜•ํƒœ.
  • ๋จผ์ € unite_n์„ ์ •์˜ํ•˜์ž. n๊ฐœ์— ๋Œ€ํ•ด์„œ๋Š” ์•ˆ๋˜๋‹ˆ 3๊ฐœ๊นŒ์ง€๋งŒ ํ•ด๋ณด์ž.
extension Summary {
 
    internal func unite0() -> Void {
        empty()
    }
 
    internal func unite1<T>(_ t: T) -> T {
        identity(t)
    }
 
    internal func unite2<T1, T2>(_ t1: T1, _ t2: T2) -> (T1, T2) {
        (t1, t2)
    }
 
    internal func unite3<T1, T2, T3>(_ t1: T1, _ t2: T2, _ t3: T3) -> ((T1, T2), T3) {
        unite(unite(t1, t2), t3)
    }
 
}
  • ๋‹ค์Œ์œผ๋กœ m_unite_n์„ ์ •์˜ํ•˜์ž.
extension Summary {
 
    internal func mUnite0() -> Void? {
        pure(empty())
    }
 
    internal func mUnite1<T>(_ mt: T?) -> T? {
        identity(mt)
    }
 
    internal func mUnite2<T1, T2>(_ mt1: T1?,
                                  _ mt2: T2?) -> (T1, T2)? {
        gather(unite(mt1, mt2))
    }
 
    internal func mUnite3<T1, T2, T3>(_ mt1: T1?,
                                      _ mt2: T2?,
                                      _ mt3: T3?) -> ((T1, T2), T3)? {
        mUnite2(mUnite2(mt1, mt2), mt3)
    }
 
}
  • ๋งˆ์ง€๋ง‰ ํ•˜๋‚˜์˜ ํ•จ์ˆ˜๋งŒ ๋” ์ •์˜ํ•˜์ž. uniteArg3.
extension Summary {
 
    internal func uniteArg3<T1, T2, T3, U>(_ f: @escaping ((T1, T2, T3) -> U)) -> (((T1, T2), T3)) -> U {
        { t12_3  in
            f(e1(e1(t12_3)), e2(e1(t12_3)), e2(t12_3))
        }
    }
 
}
  • ์ด์ œ lift ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž.
extension Summary {
 
    internal func lift2<T1, T2, U>(_ f: @escaping ((T1, T2) -> U)) -> (T1?, T2?) -> U? {
        { mt1, mt2 in
            lift(f)(mUnite2(mt1, mt2))
        }
    }
 
    internal func lift3<T1, T2, T3, U>(_ f: @escaping ((T1, T2, T3) -> U)) -> (T1?, T2?, T3?) -> U? {
        { mt1, mt2, mt3 in
            lift(uniteArg3(f))(mUnite3(mt1, mt2, mt3))
        }
    }
 
}
  • ๊ทธ๋Ÿฐ๋ฐ lift3๋กœ mUnite3์„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
extension Summary {
 
    internal func mUnite2FromLift<T1, T2>(_ mt1: T1?,
                                          _ mt2: T2?) -> (T1, T2)? {
        lift2(unite2)(mt1, mt2)
    }
 
    internal func mUnite3FromLift<T1, T2, T3>(_ mt1: T1?,
                                              _ mt2: T2?,
                                              _ mt3: T3?) -> ((T1, T2), T3)? {
        lift3(unite3)(mt1, mt2, mt3)
    }
 
}
  • ๋ญ”๊ฐ€ ์ด์ƒํ•˜๋‹ค. lift๋ฅผ ์ฐพ์•„์˜จ ์—ฌ์ •์ธ๋ฐ, ๊ทธ๊ฒฐ๊ณผ๋กœ ์ž์‹ ์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค๋‹ˆ.
  • ์ฆ‰ ๋™์น˜์ธ ๊ตฌ์กฐ๋ฅผ ๋ฐœ๊ฒฌํ•œ ๊ฒƒ์ด๋‹ค.

๋™์น˜ ๊ตฌ์กฐ

  • ์ด ๋ถ€๋ถ„์—์„œ ๋ง‰ํ˜€์„œ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์‹œ๋„๋ฅผ ํ•ด๋ณด์•˜๋‹ค.
  • ๋งŒ์ง€์ž‘ ๊ฑฐ๋ ค๋ณด๋ฉด, ํ•จ์ˆ˜๋“ค์ด ์„œ๋กœ ์ˆœํ™˜ํ•˜๋ฉด์„œ ๋‚ด๊ฐ€ ์ •์˜๋˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค๋ฅธ ํ•จ์ˆ˜๊ฐ€ ์š”๊ตฌ๋˜๋Š” ์ƒํ™ฉ์ด ํŽผ์ณ์ง„๋‹ค.
enum Veritication {
 
}
 
extension Veritication {
 
    // ํ•„์š” ํ•จ์ˆ˜
 
    internal func lift0<T>(_ transform: @escaping () -> T) -> (() -> T?) {
        { () -> T? in
            transform()
        }
    }
 
    internal func lift<T, U>(_ transform: @escaping (T) -> U) -> (Optional<T>) -> Optional<U> {
        return { (input: Optional<T>) -> Optional<U> in
            switch input {
            case .none:
                return .none
            case .some(let wrapped):
                return .some(transform(wrapped))
            }
        }
    }
 
    internal func lift2<T1, T2, U>(_ f: @escaping ((T1, T2) -> U)) -> (T1?, T2?) -> U? {
        { mt1, mt2 in
            lift(f)(mUnite2(mt1, mt2))
        }
    }
 
    internal func unite2<T1, T2>(_ t1: T1, _ t2: T2) -> (T1, T2) {
        (t1, t2)
    }
 
    // ์ฆ๋ช… ์‹œ์ž‘
 
    internal func pure<T>(_ t: T) -> T? {
        Optional(t)
    }
 
    internal func pureFromLift<T>(_ value: T) -> Optional<T> {
        lift0 { () -> T in
            value
        }()
    }
 
    internal func gather<T, U>(_ tuple: (T?, U?)) -> (T, U)? {
        switch tuple {
        case (.some(let t), .some(let u)):
            return Optional((t, u))
        default:
            return nil
        }
    }
 
    internal func gatherFromLift<T, U>(_ tuple: (Optional<T>, Optional<U>)) -> Optional<(T, U)> {
        //        mUnite2(e1(tuple), e2(tuple))
        mUnite2FromLift(e1(tuple), e2(tuple))
    }
 
    internal func mUnite2<T1, T2>(_ mt1: T1?,
                                  _ mt2: T2?) -> (T1, T2)? {
        gather(unite(mt1, mt2))
    }
 
    internal func mUnite2FromLift<T1, T2>(_ mt1: T1?,
                                          _ mt2: T2?) -> (T1, T2)? {
        lift2(unite2)(mt1, mt2)
    }
 
}

๊ฒฐ๋ก 

Monoidal Functor๋Š” Functor๊ฐ€ lift_n์„ ๊ฐ–๊ธฐ ์œ„ํ•œ ํ•„์š”์ถฉ๋ถ„์กฐ๊ฑด์ด๋‹ค.

  • Monoidal Functor๋Š” pure, gather๋งŒ ์ •์˜ํ–ˆ๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  ๊ทธ ์ƒํ™ฉ์—์„œ lift_n์ด ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๊ผด๋กœ ์ •์˜๋˜๋Š”์ง€ ํ™•์ธํ•ด๋ดค๋‹ค.
  • ๊ทธ๋žฌ๋”๋‹ˆ lift_n์ด ์ž˜ ์ •์˜๋˜์—ˆ๋‹ค!

ํ˜น์€.

  • lift_n์ด ์ •์˜๋˜๋Š” ์กฐ๊ฑด์„ ์ฐพ์•˜๋‹ค.
  • ๊ทธ๋Ÿด ๊ฒฝ์šฐ pure, gatherํ•จ์ˆ˜๋Š” ๋ฌด์กฐ๊ฑด ๋งŒ์กฑํ•œ๋‹ค.
  • ์ฆ‰, Monoidal Functor๋Š” ๋‹ค์ธ์ˆ˜ ํ•จ์ˆ˜์˜ lift๋ฅผ ์›ํ•˜๋Š” ๊ผด๋กœ ๋งŒ๋“œ๋Š” ๋…€์„์ด๋‹ค.

์–‘์ชฝ ๋ชจ๋‘ ๊ฐ™์€ ๊ฒฐ๋ก ์— ๋„๋‹ฌํ•˜๊ณ  ์žˆ๋‹ค. ์ด ๊ฒฐ๊ณผ๋ฅผ ํ†ตํ•ด Monoidal Functor๊ฐ€ Functor์™€ Monad ์‚ฌ์ด ๋ฒ”์ฃผ์— ํ•ด๋‹นํ•˜๋Š” ๋…€์„์ž„์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์™œ ๋งŽ์ด ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š”๊ฐ€?

  • ํ•จ์ˆ˜ํ˜• ์–ธ์–ด์—์„œ ๋‹ค์ธ์ˆ˜ ํ•จ์ˆ˜์˜ ์ธ์ž๋ฅผ ํŠœํ”Œ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ.
    • ๋ฐ˜๋Œ€๋กœ ๋งํ•˜๋ฉด n-tuple์„ ์ž˜ ์ง€์›ํ•˜๋Š” ์–ธ์–ด์—์„œ๋Š” ์ด ๊ฐœ๋…์ด ์ฃผ๋ฅ˜๊ฐ€ ๋˜์—ˆ์„ ๊ฒƒ.
  • ํŠœํ”Œ๋ง๊ณ  ํ•จ์ˆ˜ํ˜• ์–ธ์–ด ํ™˜๊ฒฝ์—์„œ ๋” ์ž˜ ํ™œ์šฉ๋  ์ˆ˜ ์žˆ์„ ๋งŒํ•œ ๊ฐœ๋…์„ ๋„ฃ์„ ์ˆ˜ ์žˆ๋Š”๋ฐ,
  • apply: M<T->U> -> (M<T>->M<U>)์ด๋‹ค.
  • ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์ด ๊ณง 10. Applicative Functor์ด๋‹ค.

Reference