๊ทธ๋์ Monad๋ฅผ ์ ์ฌ์ฉํ๋๊ฐ?
์ ์ฐจ์ํ์ฅ flatLift๋ ์ค์ํ ๊น?
- ๋ค๋ณ์๋ฅผ ๋ฐ์ ๋ชจ๋๋๋ฅผ ๋ฐํํ๋ ํจ์๋ ํฉ์ฑํ ์ ์๋ค.
f1: T1 -> M<U1>,f2: T2 -> M<U2>,g: (U1, U2) -> M<V>- ์ ์ธ ํจ์๊ฐ ์๋ค๊ณ ํ์.
- ์์์ ํ๋
lift2d๋ฅผg์ ์ฌ์ฉํด๋ณด์. (Monad๋ Functor๋๊น)
func lift2d<T, U, V>(_ transform: @escaping (T, U) -> V) -> (F<T>, F<U>) -> F<F<V>> {
{ ft, fu in
lift { (t: T) -> V? in
lift { (u: U) -> V in
transform(t, u)
}(fu)
}(ft)
}
}
lift2d(g) // (M<U1>, M<U2>) -> M<M<V>>- ๋น์ฐํ ์ด๋ ๊ฒ ๋์ฌ ๊ฒ์ด๋ค.
- ์ด์
f1๊ณผf2๋ฅผ ํฉ์ฑํด๋ณด์.
let t1: T1 = someT1
let t2: T2 = someT2
lift2d(g)(f1(t1), f2(t2)) // M<M<V>>- ์ด๋ ๊ฒ ํ๋ฉด f1 ํจ์์ f2 ํจ์๋ฅผ g๋ก ํฉ์ฑํ ์ ์๊ฒ ๋๋ค.
- ๊ทธ๋ฐ๋ฐ ์ด๋ ๊ฒ ํ๋ฉด
M<M<V>>๊ฐ ๋์จ๋ค. - ๋ชจ๋๋์ธ ๊ฒฝ์ฐ ์ด๊ฑธ
flatํ ์ ์์ด, ๋ณดํต ์ํ๋ ๊ฒฐ๊ณผ์ธM<V>๋ฅผ ์ป์ ์ ์๋ค.
func flatLift2d<T1, T2, U>(_ transform: @escaping (T1, T2) -> U?) -> (T1?, T2?) -> U? {
{ mt1, mt2 in
flatLift { t1 in
flatLift { t2 in
transform(t1, t2)
}(mt2)
}(mt1)
}
}
flatLift2d(g)(f1(t1), f2(t2)) // M<V>- ๋ณ์๊ฐ ๋ช๊ฐ์ด๋ ์ด๋ฐ์์ผ๋ก ํฉ์ฑํ ํจ์๋ฅผ ๋ง๋ค์ ์๋ค!
๋ฌด์์ ์๋ฏธํ๋๊ฐ?
- ๊ทธ๋ ๋ค๋ฉด ์์ฒ๋ผ ์ฐ์ฐํ ์ ์๋ค๋ ๊ฒ์ด ๋ฌด์์ด ์ข์ ๊ฑธ๊น?
Functor๋ก๋ ๋ค๋ณ์ ํจ์๋ฅผ ํฉ์ฑํ์ ๋์ ๊ฒฐ๊ณผ๊ฐ ํ์ ์ด ์ค์ฒฉ๋์ด ๋์จ๋ค.- ํ์ง๋ง
Monad๋ก๋ ์ด๋ฅผflatํ ์ ์์ด ํ์ ์ด ์ค์ฒฉ๋์ง ์๋๋ค. - ์ด๋ ๊ณง Monad ํํ์ ๋ฐํ ํจ์๋ก ๋ณํํจ์๋ฅผ ๋ค ๋ง๋ ๋ค์์ ํ๋ก๊ทธ๋๋ฐํ ์ ์์์ ๋ปํ๋ค.
- ์ฆ, ๋ณํ์ ๊ฒฐ๊ณผ์ โํ์ฅ๋ ์๋ฏธ๋ฅผ ๊ฐ์ง ํ์ (๋ชจ๋๋)โ๋ก ๋ณํํ๋๋ก ๋ง๋ค๊ณ , ์ด๊ฒ๋ค ๋ง์ผ๋ก ํ๋ก๊ทธ๋๋ฐ์ด ๊ฐ๋ฅํจ์ ์์ฌํ๋ค.
์ธ์ ์ ์ฉํ๊ฐ?
- ์ด๋ ๊ฒ๋ง ๋งํ๋ฉด ์ธ์ ์ ์ฉํ์ง ์ ๋ชจ๋ฅด๊ฒ ๋ค.
- ํก๋จ ๊ด์ฌ์ฌ๋ผ๋ ๊ฒ์ ๋ถ๋ฆฌํ ๋ ์ฌ์ฉํ๋ค.
ํก๋จ ๊ด์ฌ์ฌ

- ์ํ ๊ด๋ จ ์ํํธ์จ์ด๋ฅผ ๋ง๋ ๋ค๊ณ ์๊ฐํด๋ณด์.
- ๊ฐ๊ธฐ ์ธ๊ฐ์ ๊ธฐ๋ฅ์ ๋ค๋ฅธ ํจ์๋ ๋ชจ๋๋ก ๋ถ๋ฆฌ๋์ด ์์ ๊ฒ์ด๋ค.
- ํ์ง๋ง ์ด ์ธ๊ธฐ๋ฅ์ ์ํํ๋๋ฐ ์์ด, ๊ฐ์ ๊ธฐ๋ฅ์ ์ฒ๋ฆฌํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
ํก๋จ ๊ด์ฌ์ฌ(Cross-cutting concern)๋ ์ํํธ์จ์ด ๊ฐ๋ฐ์์ ์ฌ๋ฌ ๋ถ๋ถ์์ ๊ณตํต์ ์ผ๋ก ๋ฐ์ํ๋ ๊ธฐ๋ฅ ๋๋ ๊ด์ฌ์ฌ๋ฅผ ๋ํ๋ ๋๋ค. ์ด๋ฌํ ๊ด์ฌ์ฌ๋ค์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ๋ฌ ๋ชจ๋์ด๋ ์ปดํฌ๋ํธ์ ๊ฑธ์ณ์ ๋ฐ๋ณต์ ์ผ๋ก ๋ฐ์ํ๋ฉฐ, ๋น์ฆ๋์ค ๋ก์ง์ด๋ ์ฃผ์ ๊ธฐ๋ฅ๊ณผ๋ ๋ ๋ฆฝ์ ์ผ๋ก ์กด์ฌํฉ๋๋ค. ์ฃผ์ ๊ธฐ๋ฅ๊ณผ ๋ณ๊ฐ๋ก ์กด์ฌํ๋ ์ด๋ฌํ ๊ณตํต์ ์ธ ๊ด์ฌ์ฌ๋ค์ ์ฝ๋์ ์ค๋ณต, ๊ฐ๋ ์ฑ ์ ํ, ์ ์ง๋ณด์ ์ด๋ ค์ ๋ฑ์ ์ผ๊ธฐํ ์ ์์ต๋๋ค.
- ๋ก๊น , ์บ์ฑ, ๋ณด์, ํธ๋์ญ์ ๋ฑ์ด ํก๋จ ๊ด์ฌ์ฌ์ ํด๋นํ๋ค.
- ๋ชจ๋๋๊ฐ ์ด๋ฐ ๊ฒ ๋ถ๋ฆฌํ๋ ์ฉ๋๋ก ์ ๊ฒฉ์ด๋ค.
ํก๋จ ๊ด์ฌ์ฌ์ ์ ์ฉ
- ๋ฐฉ๋ฒ์ ๊ฐ๋จํ๋ค.
- ํก๋จ ๊ด์ฌ์ฌ์ ํด๋นํ๋ ๋ชจ๋ ํจ์์ ๋ฐํํ์ ๋ชจ๋๋ ํ์ ์ผ๋ก ๋ฐํํ๋ ํจ์๋ก ๋ฐ๊พธ๋ฉด ๋๋ค.
- ๊ทธ๋ ๊ฒ ๋๋ฉด ์ด ๋ค์ ํจ์๋ฅผ ์ฒ๋ฆฌํ ๋ โ๋ฌด์กฐ๊ฑด
flatLift๋ฅผ ํธ์ถโํด์ผ ํ๋ค. - ๋์ด๋ค.
func withdraw(_ money: Int?) -> Int? {
guard let money = money else {
self.error()
return nil
}
return money
}
func deposit(_ money: Int?) -> Int? {
guard let money = money else {
self.error()
return nil
}
return money
}
func error() -> String {
return "error"
}
let money = Optional(1000)
withdraw(money) // Optional(1000)- ์ด๋ ๊ฒ ๋ง๋ค๋ฉด
money๊ฐ ๊ฐ์ด ์์ ๋ ์ฒ๋ฆฌ๋ฅผ ํจ์ ๋ด์์ ์ฒ๋ฆฌํด์ผ ํ๋ค. withdraw,deposit๋ชจ๋ ๊ฐ์ ๋์์ ์ฒ๋ฆฌํด์ผ ํ๋ค๋ฉด, ์ด๋ฅผ ํจ์๋ก ๋ง๋ค๊ณ ์ผ์ผํ ํธ์ถํด์ค์ผ ํ๋ค.
func withdraw(_ money: Int) -> Int? {
return money
}
func deposit(_ money: Int) -> Int? {
return money
}
let result = Optional(1000).flatMap(withdraw) // Optional(1000)
switch result {
case .none:
error()
case .some(let money):
// some action
}- Monad๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๋ฐ ๊ณตํต์ ์๋ฌ์ฒ๋ฆฌ๋ฅผ ํจ์๋ฐ์ผ๋ก ๋ถ๋ฆฌํ ์ ์๊ฒ ๋๋ค.
- ์ด๋ ๊ฒ ๋๋ฉด ๋ค๋ฅธ ๋ชจ๋์์ ์ฌ์ฉํ๋ ๋์์์ ๋ฐ์ํ๋ ์๋ฌ๋ ๋ถ๋ฆฌํด์ ๊ด๋ฆฌํ ์ ์๊ฒ ๋๋ค.
๋ชจ๋๋๋ฅผ ๋์์ ํ์ฅ ๋๊ตฌ๋ก ๋ฐ๋ผ๋ณธ๋ค๋ฉด.

- ์ง๊ธ๊น์ง๋ ์ด๋ฌํ ํํ๋ง ๋ฐฐ์ ๋ค.
- ์์ฝํ๋ฉด, ๋ณํ ํจ์๋ก ๋ค์ด์ค๋ ํจ์์ ์ ๋ ฅ ์ธ์์ ํ์ ์ด Monad๊ฐ ์๋, ์ค์ ํ์ ์ผ๋ก ๋ค์ด์ค๋ ๊ฒฝ์ฐ๋ฅผ ๋ณํํ๋ ๊ฒ๋ง ์ฐ์ตํ๋ค.

- ํ์ง๋ง ์ ๋ ฅ์ผ๋ก ๋ค์ด์ค๋ ์ธ์์๋ Monad๊ฐ ์๋๋ผ๋ ๊ฒฐ๊ณผํจ์๋ก ๋ฐ๊ฟ ์ ์๋ค.
- ์์ ๋ชจ๋ ๋ณํ์ด ๊ฐ๋ฅํ๋ค.
- ๊ณ ์ฐจ์ Lift๋ฅผ ํ ๋ ํ์๋ ๊ฑด๋ฐ, ๋น์ฐํ ๋๋ค.
func flatLifte1<T1, T2, U>(_ transform: @escaping (T1, T2) -> U) -> (T1?, T2) -> U? {
{ mt1, t2 in
flatLift { t1 in
transform(t1, t2)
}(mt1)
}
}- t1์ ๊ฐ์ด ๋ค์ด์ฌ ๊ฑฐ์ผ.
- ๋ค์ด์ค๋ฉด ๋ณํํด.
- ๊ทธ๋ฆฌ๊ณ ์ดํจ์๋ฅผ flatLiftํด โ
T1? -> U?๋ก ๋ฐ๋ - ๊ทธ ํจ์์ ๋์ .
func flatLifte2<T1, T2, U>(_ transform: @escaping (T1, T2) -> U) -> (T1, T2?) -> U? {
{ t1, mt2 in
flatLift { t2 in
transform(t1, t2)
}(mt2)
}
}
func flatLifte3<T1, T2, U>(_ transform: @escaping (T1?, T2) -> U) -> (T1?, T2?) -> U? {
{ mt1, mt2 in
flatLift { t1 in
flatLift { t2 in
transform(t1, t2)
}(mt2)
}(mt1)
}
}
func flatLifte4<T1, T2, U>(_ transform: @escaping (T1, T2?) -> U) -> (T1?, T2?) -> U? {
{ mt1, mt2 in
flatLift { t1 in
flatLift { t2 in
transform(t1, t2)
}(mt2)
}(mt1)
}
}
func flatLift2d<T1, T2, U>(_ transform: @escaping (T1, T2) -> U?) -> (T1?, T2?) -> U? {
{ mt1, mt2 in
flatLift { t1 in
flatLift { t2 in
transform(t1, t2)
}(mt2)
}(mt1)
}
}- e3, e4, 2d๋ ๊ตฌํ์ด ์์ ํ ๊ฐ์ ๊ฒ์ ๋ณผ ์ ์๋ค.
- ๊ฒฐ๊ณผ์ ์ผ๋ก ๋ชจ๋๋ ํ์ ๊ฐ์ ํจ์๋ก ๋ณํํ ์ ์๋ ํจ์๊ฐ ์๋ค.

- ๋ค๋ง ์ฃผ์ํ ์ ์ด ์๋ค.
- ํ์ ๋ง์ผ๋ก๋ณด๋ฉด ๋ ๊ฒฝ๋ก๋ฅผ ํตํ ๊ฒฐ๊ณผ๊ฐ ๊ฐ์๋ณด์ด๋, ๋ค๋ฅผ ์ ์๋ค๋ ์ ์ด๋ค.
- ํ์ ๊ฒฝ๋ก์ ๋ถ์ ์ด๋ค ๊ฒฝ๋ก๋ฅผ ์ ํํ๋์ ๊ด๊ณ์์ด ๊ฒฐ๊ณผ๊ฐ ๊ฐ๋ค๋ฉด ๋ณด์กด๋ ฅ(ex: ์ค๋ ฅ)์ด๋ผ ํ๊ณ ,
- ๊ทธ๋ ์ง ์์ ๊ฒ์ ๋น๋ณด์กด๋ ฅ์ด๋ผ ํ์๋ค.
flatLift์ฐ์ฐ์ ๊ฒฝ์ฐ ๋น๋ณด์กด๋ ฅ๊ณผ ๊ฐ์ ํน์ง์ ๊ฐ๋๋ค ์ดํดํ๋ฉด ๋๊ฒ ๋ค.