๊ณ ์ฐจ์ 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
- ์ด๋ ต๊ฒ ์ ์์ง๋ง ์์ ์ฐ์ฐ์ ์ํ์ ์ผ๋ก ์ ์ ๊ฒ ๋ฟ์ด๋ค.
- ๊ทธ๋ฆฌ๊ณ ์ฐ๋ฆฌ ์ด๋ฐ ๋ฌธ์ ํ์ด๋ณธ์ ์๋ค.
- ์ด๊ฑฐ ์ด๋ป๊ฒ ํ์๋.
- 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))
}