Functor๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

Functor

Functor: ์ž„์˜์˜ ํƒ€์ž… T, U๊ฐ€ ์ฃผ์–ด์กŒ์„ ๋•Œ, ์—ฐ์‚ฐ lift์ด ์ •์˜๋˜๋Š” 01. Type Constructor F

lift: (T -> U) -> (F(<T>) -> F(<U>))

  • T->U์ธ ํ•จ์ˆ˜๊ฐ€ ์žˆ์„ ๋•Œ, ๊ฐ๊ฐ์˜ ์›์†Œ๋ฅผ 01. Type Constructor F๋กœ ๊ฐ์‹ธ๋Š” ํ•จ์ˆ˜๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ์œผ๋ฉด Functor
  • ์—ฌ๊ธฐ์„œ (T->U)๋กœ ๊ฐ€๋Š” ๊ฑด ๋‚ด๋ถ€์— ๋“ค์–ด๊ฐ„ ๊ฐ’์„ ๋ณ€ํ˜• ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด์ œ๋ถ€ํ„ฐ ์ด๊ฑธ transform์ด๋ผ ๋ถ€๋ฅด๊ฒ ๋‹ค.
  • ๋Œ€์ž…ํ•ด์„œ ์ƒ๊ฐํ•ด๋ณด์ž.

Optional

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))
        }
    }
}
  • transform์„ ์ธ์ž๋กœ ๋ฐ›์•„ Optional<T>๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„ Optional<U>๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ์ด๊ฒŒ ๋ช…ํ™•ํžˆ ์ •์˜๋˜๋‹ˆ Optional์€ Functor์ด๋‹ค.

Array

internal func lift<T, U>(_ transform: @escaping (T) -> U) -> ([T]) -> [U] {
    return { (input: [T]) -> [U] in
        var result: [U] = []
        for index in input.indices {
            result.append(transform(input[index]))
        }
        return result
    }
}

Result

internal func lift<T, U>(_ transform: @escaping (T) -> U) -> (Result<T, Error>) -> Result<U, Error> {
    return { (input: Result<T, Error>) -> Result<U, Error> in
        switch input {
        case .failure(let error):
            return .failure(error)
        case .success(let value):
            return .success(transform(value))
        }
    }
}

๋ณดํ†ต์˜ ํ‘œํ˜„ ๋ฐฉ๋ฒ•

  • ๋ณดํ†ต์€ ์ €๋ ‡๊ฒŒ <T, U>๋ฅผ ์ง์ ‘ ์„ ์–ธํ•ด๋‘์ง€ ์•Š๊ณ , ํƒ€์ž… ๋‚ด์—์„œ ๊ฒฐ๊ณผ ํƒ€์ž…๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ์„ ์ˆ˜ ์žˆ๊ฒŒ ์•ˆ์—์„œ ๊ตฌํ˜„ํ•œ๋‹ค.
  • ๋ชจ๋“  Functor์— ๋Œ€์‘๋˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๊ฐ€ ๋‹ค ์ € ๊ตฌํ˜„์ฒด๋ฅผ ๊ฐ–๊ณ  ์žˆ์ง€๋Š” ์•Š์œผ๋ฉฐ, Array, Set๊ณผ ๊ฐ™์ด Sequence๋กœ ๋ฌถ์ด๋Š” ๊ฒฝ์šฐ์—๋Š” ์ƒ์œ„ ํƒ€์ž…์˜ ํ”„๋กœํ† ์ฝœ์ด๋‚˜ ํด๋ž˜์Šค์—์„œ ๊ตฌํ˜„ํ•ด๋‘”๋‹ค.
  • ์ด ๋ถ€๋ถ„์€ ์–ธ์–ด๋งˆ๋‹ค ๊ตฌํ˜„์ด ๋‹ฌ๋ผ ๊ฐœ๋…์ ์œผ๋กœ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ์ข‹์„ ๋“ฏ.
internal enum Optional<Wrapped> {
    case none
    case some(Wrapped)
    
    func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> U? {
        switch self {
        case .none:
            return .none
        case .some(let wrapped):
            return try .some(transform(wrapped))
        }
    }
}
  • ๋ณดํ†ต lift๋ผ ๊ตฌํ˜„ ์•ˆ๋˜์–ด ์žˆ๊ณ  map์œผ๋กœ ๋˜์–ด ์žˆ๋‹ค.

์–ด๋–ป๊ฒŒ Functor๋ฅผ ๊ตฌํ˜„ํ• ๊นŒ?

  • ์ด์ œ ์œ„์—์„œ ๋Œ€ํ‘œ์ ์ธ Type Constructor๋“ค์ด Functor์ž„์„ ์•Œ์•˜๋‹ค.
  • ์ฆ‰, Optional, Array, Result๋Š” Functor์ด๋‹ค.
  • ๊ทธ๋ ‡๋‹ค๋ฉด ๋ณดํ†ต ์šฐ๋ฆฌ๋Š” ์ด๊ฑธ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ• ๊นŒ?
  • Functor๋ผ๋Š” ํ”„๋กœํ† ์ฝœ์„ ๋งŒ๋“ค๋“ , ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๋“  ํ•œ ๋‹ค์Œ์— ์ด๊ฑธ ์ƒ์†ํ•˜๊ฒŒ ํ•ด์„œ ๊ธฐ๋ณธ ๋™์ž‘์„ ์ œ๊ณตํ•  ๊ฒƒ์ด๋‹ค.

AllAboutMonad_01_FunctorInProgramming_0

  • ๊ทธ๋Ÿฐ๋ฐ Swift์—์„œ ๋ณด์•˜์„ ๋•Œ๋Š” ์™„์ „ํžˆ ์ด๋Ÿฐ ๊ฐœ๋…๋„๋กœ ๊ตฌํ˜„๋œ ๊ฒƒ ๊ฐ™์ง€๋Š” ์•Š๋‹ค.
  • Set, Array๊ฐ™์€ ๊ฒฝ์šฐ๋Š” Sequence Protocol์„ ์ƒ์†๋ฐ›์•„ ์ฒ˜๋ฆฌ๋˜๊ณ ,
  • Optional์˜ ๊ฒฝ์šฐ์—๋Š” ์ž์ฒด์ ์œผ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.
  • ์™œ ์ด๋ ‡๊ฒŒ ์ฒ˜๋ฆฌํ–ˆ๋Š”์ง€๋Š” ์ถ”๊ฐ€์ ์œผ๋กœ ์•Œ์•„๋ด์•ผ ํ•  ๋“ฏ.

Functor lift ํ•จ์ˆ˜์˜ ์ถ”๊ฐ€ ์กฐ๊ฑด

  • ์•ž์—์„œ ์–ด๋ ค์šธ๊นŒ๋ด ์•ˆ์ ์—ˆ๋‹ค.
  • lift ํ•จ์ˆ˜๋Š” T->U๋กœ ๊ฐ€๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฐ›์•„ F(T)๋ฅผ ๋ฐ›์•„ F(U)๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ์ด lift ํ•จ์ˆ˜๊ฐ€ ๋งŒ์กฑํ•ด์•ผ ํ•˜๋Š” ๋‘๊ฐ€์ง€ ์กฐ๊ฑด์ด ์žˆ๋‹ค.

ํ•จ์ˆ˜์˜ ํ•ญ๋“ฑ์„ฑ

id_T = (T -> T)
id_F<T> = (F(T) -> F(T))

lift = (X -> Y) -> (F<X> -> F<Y>)

lift(id_T) = id_F<T>
  • ํ•ญ๋“ฑํ•จ์ˆ˜๋ฅผ id๋ผ ํ•˜์ž. (identity)
  • T->T์ธ ํ•ญ๋“ฑํ•จ์ˆ˜๋Š” id_T๋ผ๊ณ  ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • F(T)->F(T)์ธ ํ•ญ๋“ฑํ•จ์ˆ˜๋Š” id_F<T>๋ผ๊ณ  ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • lift ์ด๋ผ๋Š” ํ•จ์ˆ˜๋Š” (X -> Y) -> (F<X> -> F<Y>) ๋ผ๊ณ  ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด ์—ฐ์‚ฐ์˜ ๊ฒฐ๊ณผ๋Š” ๋ญ๊ฐ€ ๋‚˜์˜ฌ์ง€ ๋ชจ๋ฅธ๋‹ค.
  • ๊ทธ๋Ÿฐ๋ฐ lift์˜ ์ธ์ž๋กœ ํ•ญ๋“ฑํ•จ์ˆ˜๋ฅผ ๋„ฃ์—ˆ๋‹ค๋ฉด, ๊ฒฐ๊ณผ ์—ญ์‹œ ํ•ญ๋“ฑํ•จ์ˆ˜๊ฐ€ ๋‚˜์™€์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
  • ์‚ฌ์‹ค ํ˜•ํƒœ๋งŒ ๋ด์„œ๋Š” ์ž๋ช…ํ•˜๊ฒŒ ๊ทธ๋Ÿฐ ๊ฒƒ ๊ฐ™์œผ๋‚˜, ์ˆ˜ํ•™์ ์œผ๋กœ ์—„๋ฐ€ํ•˜๊ฒŒ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์— ๊ฐ€๊น๋‹ค.
  • (๊ทธ๋ž˜์„œ ๊ฐ€์žฅ ๋ฐ‘์— ๋„ฃ์—ˆ๋‹ค.)

ํ•จ์ˆ˜์˜ ํ•ฉ์„ฑ ๊ด€๊ณ„ ๋ณด์กด

f = (T -> U)
g = (U -> V)

lift = (X -> Y) -> (F<X> -> F<Y>)

h = gโˆ˜f
lift(h) = lift(gโˆ˜f) = lift(g)โˆ˜lift(f)

์ฆ‰, 
lift(gโˆ˜f) = lift(g)โˆ˜lift(f)
  • ํ•จ์ˆ˜ h๊ฐ€ g์™€ f์˜ ํ•ฉ์„ฑ์ด๋ผ๊ณ  ํ•œ๋‹ค๋ฉด,
  • ์ด h๋ฅผ liftํ•œ ๊ฒฐ๊ณผ ์—ญ์‹œ g์™€ f๋ฅผ liftํ•œ ๊ฒฐ๊ณผ์˜ ํ•ฉ์„ฑ๊ณผ ๊ฐ™๋‹ค. (lift(g)โˆ˜lift(f))
func f(_ x: Int) -> Int {
    return x + 1
}
 
func g(_ x: Int) -> Int {
    return x * 2
}
 
func h(_ x: Int) -> Int {
    return g(f(x))
}
 
let optional = Optional.some(10)
let result1 = lift({ h($0) })(optional) // Optional.some(22)
let result2 = lift({ g($0) })(lift({ f($0) })(optional)) // Optional.some(22)
 
let array = [3, 4, 5, 6]
    let result1 = lift({ h($0) })(array) // [8, 10, 12, 14]
    let result2 = lift({ g($0) })(lift({ f($0) })(array)) // [8, 10, 12, 14]
 
let result: Result<Int, Error> = .success(10)
let result1 = lift({ h($0) })(result) // success(22)
let result2 = lift({ g($0) })(lift({ f($0) })(result)) // success(22)
 
  • ์ด๊ฒƒ๋„ ์—„๋ฐ€ํ•œ ์ฆ๋ช…์€ ๋ชปํ•˜๊ฒ ์ง€๋งŒ ๊ฒฝํ—˜์ ์œผ๋กœ ์ฐธ์ž„์„ ์–ด๋ ต์ง€ ์•Š๊ฒŒ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
  • (๊ทธ๋ž˜์„œ ๊ฐ€์žฅ ๋ฐ‘์— ๋„ฃ์—ˆ๋‹ค.)

Reference