๊ณ ์ฐจ์› Lift์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž. (map)

High Dimensional lift

  • ์•ž์—์„œ ๋ฐฐ์šด lift์€ ๊ธฐ๋ณธ์ ์œผ๋กœ 1๋ณ€์ˆ˜๋ฅผ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜์ด๋‹ค.
  • ์ธ์ˆ˜๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ์ด๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ?
  • ์ฆ‰, (T, U) -> V๋กœ ์ •์˜๋˜๋Š” transform ํ•จ์ˆ˜๋ฅผ lift์œผ๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ์„๊นŒ?
  • ์•ž์œผ๋กœ ์„ค๋ช…ํ•  ๋ณ€์ˆ˜ ์ด๋ฆ„์— ๋Œ€ํ•ด ์•„๋ž˜์— ์ •๋ฆฌํ•ด๋‘๊ฒ ๋‹ค.
ft = T๋ฅผ ๊ฐ์‹ธ๋Š” Functor, ์—ฌ๊ธฐ์„œ๋Š” Optional
fu = U๋ฅผ ๊ฐ์‹ธ๋Š” Functor, ์—ฌ๊ธฐ์„œ๋Š” Optional
f_u = u๋ฅผ ๊ณ ์ •์‹œํ‚จ ํ•จ์ˆ˜. T๋ฅผ ๋ฐ›์•„ V๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
f_t = t๋ฅผ ๊ณ ์ •์‹œํ‚จ ํ•จ์ˆ˜. U๋ฅผ ๋ฐ›์•„ V๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜

lift1

  • ์ผ๋‹จ ๊ฐœ๋…์ดํ•ด๋ฅผ ์œ„ํ•ด ๋‹ค์Œ์˜ ํ˜•ํƒœ์˜ lift ํ•จ์ˆ˜๋ถ€ํ„ฐ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณด์ž.

(T, U) -> V๋ฅผ (F<T>, U) -> F<V>๋กœ ๋ณ€ํ™˜ํ•˜๋Š” lift1 ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด๋ผ.

  • ์‰ฝ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด Functor์— ํ•ด๋‹นํ•˜๋Š” ํƒ€์ž…F์„ 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))
        }
    }
}
 
func lift1<T, U, V>(transform: @escaping (T, U) -> V) -> (Optional<T>, U) -> Optional<V> {
    return { (ft: Optional<T>, u: U) in
        let f_u = { (t: T) -> V in
            transform(t, u)
        }
        return lift(transform: f_u)(ft)
    }
}
  • u๋Š” ์ œ๋Œ€๋กœ ์ฃผ์–ด์ ธ ์žˆ์œผ๋‹ˆ, Optional<T>์ธ ft์˜ ์›๋ž˜ ์•Œ๋งน์ด๋ฅผ ๋ฐ›์•„ V๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค๊ณ ,
  • ์ด๊ฑธ liftํ•จ์ˆ˜์— ๋„ฃ์–ด๋‚˜์˜จ ๊ฒฐ๊ณผ์ธ Optional<T> -> Optional<V> ํ˜•ํƒœ์˜ ํ•จ์ˆ˜์— ft๋ฅผ ๋„ฃ์–ด์ฃผ์–ด ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ ๋ฐ›์ž.

lift2

(T, U) -> V๋ฅผ (T, F<U>) -> F<V>๋กœ ๋ณ€ํ™˜ํ•˜๋Š” lift2 ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด๋ผ.

  • ์‰ฝ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด Functor์— ํ•ด๋‹นํ•˜๋Š” ํƒ€์ž…F์„ 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))
        }
    }
}
 
func lift2<T, U, V>(transform: @escaping (T, U) -> V) -> (T, Optional<U>) -> Optional<V> {
    return { (t: T, fu: Optional<U>) in
        let f_t = { (u: U) -> V in
            return transform(t, u)
        }
        return lift(transform: f_t)(fu)
    }
}
  • ๋งˆ์ฐฌ๊ฐ€์ง€์˜ ์›๋ฆฌ๋‹ค.
  • fu๊ฐ€ Optional<U>๋กœ ๋“ค์–ด์™”์œผ๋‹ˆ, t๋ฅผ ๊ณ ์ •์‹œํ‚ค๊ณ  fu์•ˆ์— ์žˆ๋Š” ๊ฐ’์ธ U๋ฅผ ๋ฐ›์•„ V๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ณ€ํ™˜ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜์ž.
  • ๊ทธ๋ฆฌ๊ณ  ์ด ํ•จ์ˆ˜๋Š” ์ด์ œ lift์— ๋„ฃ์„ ์ค€๋น„๊ฐ€ ๋˜์—ˆ์œผ๋‹ˆ (Functor๋กœ ๊ฐ์‹ธ์ ธ ์žˆ์ง€ ์•Š์Œ) ์ด๊ฑธ ๋„ฃ์–ด ๋‚˜์˜ค๋Š” ๊ฒฐ๊ณผ์ธ
  • Optional<U> -> Optional<V>ํ˜•ํƒœ์˜ ํ•จ์ˆ˜์— fu๋ฅผ ๋„ฃ์–ด Optional<V>ํ˜•ํƒœ์˜ ๊ฐ’์„ ๋ฐ›๋Š” โ€œํ•จ์ˆ˜โ€๋ฅผ ๋ฐ˜ํ™˜๋ฐ›์ž.

2 dimentional lift

  • ์ด์ œ ๋‘๊ฐœ๋ฅผ ํ•ฉ์ณ์„œ ๋‹ค์Œ์„ ํ’€์–ด๋ณด์ž.

(T, U) -> V๋ฅผ (F<T>, F<U>) -> F<F<V>>๋กœ ๋ณ€ํ™˜ํ•˜๋Š” lift2d ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด๋ผ.

  • ์‰ฝ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด Functor์— ํ•ด๋‹นํ•˜๋Š” ํƒ€์ž…F์„ Optional๋กœ ์ƒ๊ฐํ•ด๋ณด์ž.
  • ์ž˜ ์ƒ๊ฐํ•ด๋ณด๋ฉด ์œ„ ๋ฌธ์ œ๋Š” lift1, lift2๋ฅผ ์„ž์œผ๋ฉด ๋œ๋‹ค. ใ…‹ใ…‹
((T, U) -> V)
      |
   lift1(์ ์šฉ)
      |
((F<T>, U) -> F<V>)
      |
   lift2(์ ์šฉ)
      |
((F<T>, F<U>) -> F<F<V>>)
func lift2d(T, U, V)(transform: @escaping (T, U) -> V) -> (Optional<T>, Optional<U>) -> Optional<Optional<V>> {
    let lift1Result = lift1(transform: transform) // ๊ฒฐ๊ณผ ํƒ€์ž…: (Optional<T>, U) -> Optional<V>
    let lift2Result = lift2(transform: lift1Result) // ๊ฒฐ๊ณผ ํƒ€์ž…: (Optional<T>, Optional<U>) -> Optional<V>
    return lift2Result
}
 
// ๋˜๋Š”
 
func lift2d<T, U, V>(transform: @escaping (T, U) -> V) -> (Optional<T>, Optional<U>) -> Optional<Optional<V>> {
    lift2(transform: lift1(transform: transform))
}
 

lift์œผ๋กœ๋ถ€ํ„ฐ ๋ฐ”๋กœ lift2d ๋งŒ๋“ค๊ธฐ

  • ์ด์ œ ((T, U) -> V) -> ((F<T>, F<U>) -> F<F<V>>) ์ด ํ˜•ํƒœ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ์€ ์•Œ์•˜๋‹ค.
  • ๊ทผ๋ฐ ์ง€๊ธˆ์€ lift1, lift2๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ทธ๊ฑธ ์ฆ๋ช…ํ–ˆ์„ ๋ฟ, lift์„ ๋ฐ”๋กœ ์‚ฌ์šฉํ•ด์„œ ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜์ง€๋Š” ์•Š์•˜๋‹ค.
  • ์ด๊ฑธ ํ•ด๋ด์•ผ ๋‚˜์ค‘์— Monad ์ดํ•ด๊ฐ€ ์‰ฝ๋‹ค.

(T, U) -> V๋ฅผ (F<T>, F<U>) -> F<F<V>>๋กœ ๋ณ€ํ™˜ํ•˜๋Š” lift2d ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด๋ผ. ๋‹จ lift1, lift2๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  lift์œผ๋กœ๋งŒ ๋งŒ๋“ค์–ด๋ผ.

  • ์‰ฝ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด Functor์— ํ•ด๋‹นํ•˜๋Š” ํƒ€์ž…F์„ 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))
        }
    }
}
 
func lift2d<T, U, V>(_ transform: @escaping (T, U) -> V) -> (Optional<T>, Optional<U>) -> Optional<Optional<V>> {
    return { (ft: Optional<T>, fu: Optional<U>) in
        let g = { (t: T) -> Optional<V> in
            let f_t = { (u: U) -> V in
                return transform(t, u)
            }
            return lift(transform: f_t)(fu)
        }
        return lift(transform: g)(ft)
    }
}
 
// ๋˜๋Š”
 
func lift2d<T, U, V>(_ transform: @escaping (T, U) -> V) -> (Optional<T>, Optional<U>) -> Optional<Optional<V>> {
    return { (ft: Optional<T>, fu: Optional<U>) in
        lift { (t: T) -> Optional<V> in
            lift { (u: U) -> V in
                transform(t, u)
            }(fu)
        }(ft)
    }
}
 
// ๋˜๋Š”
 
func lift2d<T, U, V>(_ transform: @escaping (T, U) -> V) -> (Optional<T>, Optional<U>) -> Optional<Optional<V>> {
    { (ft: Optional<T>, fu: Optional<U>) in
        lift { (t: T) -> Optional<V> in
            lift { (u: U) -> V in
                transform(t, u)
            }(fu)
        }(ft)
    }
}
 
// ๋˜๋Š”
 
func lift2d<T, U, V>(_ transform: @escaping (T, U) -> V) -> (Optional<T>, Optional<U>) -> Optional<Optional<V>> {
    { (ft, fu) in
        lift { (t: T) -> Optional<V> in
            lift { (u: U) -> V in
                transform(t, u)
            }(fu)
        }(ft)
    }
}
 
// ๋˜๋Š”
 
func lift2d<T, U, V>(_ transform: @escaping (T, U) -> V) -> (Optional<T>, Optional<U>) -> Optional<Optional<V>> {
    { ft, fu in
        lift { (t: T) -> Optional<V> in
            lift { (u: U) -> V in
                transform(t, u)
            }(fu)
        }(ft)
    }
}
 
// ๋˜๋Š”
 
func lift2d<T, U, V>(_ transform: @escaping (T, U) -> V) -> (T?, U?) -> V?? {
    { ft, fu in
        lift { (t: T) -> V? in
            lift { (u: U) -> V in
                transform(t, u)
            }(fu)
        }(ft)
    }
}
  • ์•ž์—์„œ๋Š” ๋ฆฌํ„ด ํƒ€์ž… ํ•จ์ˆ˜์˜ ์ฒซ๋ฒˆ์งธ ์ธ์ž๊ฐ€ Optional<T>๊ฑฐ๋‚˜, ๋‘๋ฒˆ์งธ ์ธ์ž๊ฐ€ Optional<U>์˜€๊ธฐ ๋•Œ๋ฌธ์—
  • ๋‘˜์ค‘ ํ•˜๋‚˜๋Š” Functor๊ฐ€ ์•„๋‹Œ ๊ฐ’์œผ๋กœ ๋“ค์–ด์™”์—ˆ๋‹ค.
  • ๊ทธ๋žฌ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ’์ด ํ•˜๋‚˜๊ฐ€ ๊ณ ์ •๋œ ์ƒํ™ฉ์—์„œ Functor๋กœ ๋“ค์–ด์˜ค๋Š” ์ธ์ž๋ฅผ ์—†์•ค ํ˜•ํƒœ์˜ ์ƒˆ๋กœ์šด transformํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด,
  • ์ด๋ฅผ lift์— ๋„ฃ์–ด์ฃผ์—ˆ๋‹ค. (๊ทธ๋ž˜์•ผ lift ํ•จ์ˆ˜๊ฐ€ ๋™์ž‘ํ•˜๋‹ˆ๊นŒ.)
  • ๊ทธ๋Ÿฐ๋ฐ ์ด๋ฒˆ์—๋Š” ๋‘˜๋‹ค Functor๋กœ ๋“ค์–ด์˜จ๋‹ค. ์•ž์—์„œ ์‚ฌ์šฉํ•œ ํŠธ๋ฆญ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.
  • ๊ทธ๋ž˜์„œ ์—ฌ๊ธฐ์„œ๋Š” ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•œ๋‹ค.
  • ์ผ๋‹จ ์–ด๋– ํ•œ ํ•จ์ˆ˜๋ฅผ ๊ฐ€์ •ํ•˜๊ณ , ์–˜๊ฐ€ T -> Optional<T>๋กœ ๋‚˜์˜ฌ๊ฑฐ๋ผ๊ณ  ๊ฐ€์ •ํ•˜๋Š” ๊ฑฐ๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  ๊ทธ ํ•จ์ˆ˜๋‚ด์—์„œ ๋‹ค์‹œ U -> V๋ฅผ ๋งŒ๋“ค์–ด lift์— ๋„ฃ์–ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.
  • ๊ทธ๋Ÿฌ๋ฉด ์˜๋ฌธ์ด ์ƒ๊ธด๋‹ค.
  • ์–ด ์•„๊นŒ๋Š” f_u, f_t ํ•จ์ˆ˜์˜ ๋ฆฌํ„ด๊ฐ’์ด V์˜€๋Š”๋ฐ ์ง€๊ธˆ์€ Optional<V>์ธ๋ฐ?
  • ๊ทธ๋Ÿฌ๋ฉด lift์„ ์“ฐ๋ฉด Optional<Optional<V>>๊ฐ€ ๋‚˜์˜ค๋Š”๋ฐ?
  • ๊ทธ๋ž˜์„œ ์ด ๋ฌธ์ œ๋ฅผ ๋‹ค์‹œ ์ž˜๋ณด๋ฉด ๊ฒฐ๊ณผ ํ•จ์ˆ˜์˜ ๋ฆฌํ„ด๊ฐ’์ด Optional<Optional<V>>์ด๋‹ค.
  • ๊ทธ๋Ÿผ ์ž˜ ๋”ฐ๋ผ ์˜จ๊ฒƒ์ด ๋งž๋‹ค.

3 Demensional lift

  • ๊ทธ๋Ÿผ 3์ฐจ์›๋„ ๊ฐ€๋Šฅํ•˜๊ฒ ์ง€?

(T1, T2, T3) -> U๋ฅผ (F<T1>, F<T2>, F<T3>) -> F<F<F<U>>>๋กœ ๋ณ€ํ™˜ํ•˜๋Š” lift3d ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด๋ผ. ๋‹จ liftํ•จ์ˆ˜๋งŒ ์‚ฌ์šฉํ•œ๋‹ค.

  • ์‰ฝ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด Functor์— ํ•ด๋‹นํ•˜๋Š” ํƒ€์ž…F์„ 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))
        }
    }
}
 
func lift3d<T1, T2, T3, U>(_ transform: @escaping (T1, T2, T3) -> U) -> (T1?, T2?, T3?) -> U??? {
    { ft1, ft2, ft3 in
        lift { (t1: T1) in
            lift { (t2: T2) in
                lift { (t3: T3) in
                    transform(t1, t2, t3)
                }(ft3)
            }(ft2)
        }(ft1)
    }
}
  • ๋ช‡์ฐจ์›์ด๋“  ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฌด์Šจ ์˜๋ฏธ๊ฐ€ ์žˆ๋Š”๊ฐ€?

๋‹ค๋ณ€์ˆ˜ ํ•จ์ˆ˜๋ฅผ ์ผ๋ณ€์ˆ˜ ํ•จ์ˆ˜์˜ ์—ฐ์†๋œ ๋™์ž‘์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

  • In general,
  • for an operation on single-variable functions, O
  • its dimensional-extension, O is given by
O^3\_{tuv}\[f(t, u, v)\] \equiv O\_{t}\[O\_{u}\[O\_{v}\[f(t, u, v)\]*{fix\_tu}\]*{fix\_t}\]
  • ์–ด๋ ต๊ฒŒ ์ ์—ˆ์ง€๋งŒ ์œ„์˜ ์—ฐ์‚ฐ์„ ์ˆ˜ํ•™์ ์œผ๋กœ ์ ์€ ๊ฒƒ ๋ฟ์ด๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  ์šฐ๋ฆฌ ์ด๋Ÿฐ ๋ฌธ์ œ ํ’€์–ด๋ณธ์  ์žˆ๋‹ค.
  • ์ด๊ฑฐ ์–ด๋–ป๊ฒŒ ํ’€์—ˆ๋ƒ.
  • x, y, z ๋‹ค๋ณ€์ˆ˜์— ๋Œ€ํ•œ ์ ๋ถ„์ด์ง€๋งŒ,
  • ์•ˆ์—์„œ๋ถ€ํ„ฐ ๋‹ค๋ฅธ ๋ณ€์ˆ˜๊ฐ€ ๊ณ ์ •๋˜์–ด ์žˆ์„ ๊ฑฐ๋ผ ๊ฐ€์ •ํ•˜๊ณ  ๋ณ€์ˆ˜๋กœ ๋ƒ„๊ฒจ์„œ ํ’€์—ˆ๋‹ค.
  • ์ด์™€ ๊ฐ™์€ ์›๋ฆฌ๋กœ ๋‹ค๋ณ€์ˆ˜ ํ•จ์ˆ˜์— ๋Œ€ํ•ด ์ด๊ฑธ ์ผ๋ณ€์ˆ˜ ํ•จ์ˆ˜์˜ ์—ฐ์†๋œ ๋™์ž‘์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์„œ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
func integrate(_ f: (Double) -> Double, _ lower: Double, _ upper: Double) -> Double {
    Array(stride(from: lower, through: upper, by: 0.1))
        .reduce(.zero) { $0 + f($1) }
}
 
func f_x(x: Double) -> Double {
    integrate({ (y: Double) in
        integrate({ (z: Double) in
            Double(pow(x, pow(y, z)))
        }, 0, 1)
    }, 0, 1)
}
 
integrate(f_x, 0, 1)
  • integrate๋ผ๋Š” 1๋ณ€์ˆ˜ ํ•จ์ˆ˜์— ๋Œ€ํ•œ ์ ๋ถ„ ๋ฐฉ์‹์„ ์ •์˜ํ•˜๊ณ ,
  • ์ด๋ฅผ ์—ฐ์†์ ์œผ๋กœ ์‚ฌ์šฉํ•ด์„œ ๋‹ค๋ณ€์ˆ˜ ํ•จ์ˆ˜์— ๋Œ€ํ•œ ์ ๋ถ„์„ ์ •์˜ํ–ˆ๋‹ค.
  • ์—ฌ๊ธฐ์„œ ๋‹ค๋ณ€์ˆ˜ ํ•จ์ˆ˜์— ๋Œ€ํ•ด ์ปค๋ง๊นŒ์ง€ ์ ์šฉํ•˜๋ฉด integrate ํ•จ์ˆ˜๋ฅผ ๋” ๊น”๋”ํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.
public func curry<A, B>(_ f: @escaping (A) -> B) -> (A) -> B {
    { a in f(a) }
}
 
public func curry<A, B, C>(_ f: @escaping (A, B) -> C) -> (A) -> (B) -> C {
    { a in { b in f(a, b) } }
}
 
public func curry<A, B, C, D>(_ f: @escaping (A, B, C) -> D) -> (A) -> (B) -> (C) -> D {
    { a in { b in { c in f(a, b, c) } } }
}
 
func f_x(x: Double) -> Double {
    curry(integrate)({ (y: Double) in
        curry(integrate)({ (z: Double) in
            Double(pow(x, pow(y, z)))
        })(0)(1)
    })(0)(1)
}

๋ฆฌ์ŠคํŠธ์— ์ ์šฉ

func lift<T, U>(_ transform: @escaping (T) -> U) -> ([T]) -> [U] {
    { ft in
        var result = [U]()
        ft.forEach { t in
            result.append(transform(t))
        }
        return result
    }
}
 
func lift2d<T, U, V>(_ transform: @escaping (T, U) -> V) -> ([T], [U]) -> [[V]] {
    { ft, fu in
        lift { t in
            lift { u in
                transform(t, u)
            }(fu)
        }(ft)
    }
}

์™œ ๋ฐฐ์› ๋‚˜?

  • ๋‚˜์ค‘์— ๋ชจ๋‚˜๋“œ ๊ฐ€๋ฉด ์ฐจ์› ํ™•์žฅํ•ด์„œ ์œ„์™€ ๊ฐ™์€ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์•ผํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค.(flatlift)
  • ๊ทธ๋•Œ๋ฅผ ์œ„ํ•œ ์—ฐ์Šต ๊ณผ์ •.
  • ์ง์ ‘์ ์œผ๋กœ lift์˜ ์ฐจ์› ํ™•์žฅ์€ ํฐ ๊ด€๊ณ„๋Š” ์—†๋‹ค.

์ถ”๊ฐ€ ์ •๋ณด

  • lift ํ•จ์ˆ˜๋Š” swift์˜ map ํ•จ์ˆ˜์™€ ๋™์ผํ•˜๋‹ค.

์ถœ๋ ฅ ๊ฒฐ๊ณผ

private func testOptionalLift2d() {
    let x = Optional(3)
    let y = Optional(4)
 
    let result = lift2d { x, y in
        x+y
    }(x, y)
 
    print(result) // Optional(Optional(7)
}
 
private func testArrayLift2d() {
    let x = [3, 4, 5, 6]
    let y = [10, 20, 30]
 
    let result = lift2d { x, y in
        x+y
    }(x, y)
 
    print(result) // [[13, 23, 33], [14, 24, 34], [15, 25, 35], [16, 26, 36]]
}
 
private func testResultLift2d() {
    let x: Result<Int, Error> = .success(10)
    let y: Result<Int, Error> = .success(3)
 
    let result = lift2d { x, y in
        x+y
    }(x, y)
 
    print(result) // success(Swift.Result<Swift.Int, Swift.Error>.success(13))
}
 

Reference