iOS/Swift
[Swift] 모나드(Monad)
year.number
2022. 8. 15. 15:45
모나드
- 값을 어딘가에 포장하는 개념에 대한 이해에서 출발한다
- 함수객체(Functor)와 모나드(Monad)는 특정 기능이 아닌 디자인 패턴 혹은 자료구조라고 할 수 있다
모나드가 갖춰야하는 조건 3가지
- 타입을 인자로 받는 타입
- 특정 타입의 값을 포장한 것을 반환하는 함수가 존재
- 포장된 값을 변환하여 같은 형태로 포장하는 함수가 존재
모나드의 대표적인 예시:
🔥 옵셔널 - 값이 있을지 없을지 모르는 상태를 박스에 담아두는 것
옵셔널은
(1) Wrapped 타입을 인자로 받는 제네릭 타입이다
(2) Optional<Int>, init(2) 처럼 다른 타입의 값을 갖는 상태의 컨텍스트를 생성할 수 있다
(3) 옵셔널은 컨테이너와 값을 갖기 때문에 맵 함수를 사용할 수 있다
모나드를 이해하기 위해 필요한 개념
1. 컨텍스트(Context)
2. 함수객체(Functor)
컨텍스트(Context)
스위프트에서 컨텍스트는 콘텐츠를 담은 그 무엇인가(박스)이다
ex)
2라는 숫자를 옵셔널로 둘러싸면 컨텍스트 안에 2라는 콘텐츠가 들어가있는 것이다.
= 컨텍스트는 2라는 값을 가지고 있다
값이 없는 옵셔널 상태라면 컨텍스트는 존재하지만 내부에 값이 없다고 할 수 있다
// MARK: 컨텍스트
func add(_ num: Int) -> Int {
return num + 3
}
print(add(2)) //순수값 2를 전달하면 정상적으로 함수를 실행할 수 있다
// print(Optional(2)) 순수값이 아닌 컨텍스트로 둘러싸인 값이 전달되었기 때문에 오류
// map 메서드를 사용하여 옵셔널 연산
print(Optional(2).map(add)) //Optional(5)
//map함수는 연산 결과를 다시 컨텍스트에 넣어 반환
함수객체
닫힌 함수객체(Endofunctor)
- 자신의 컨텍스트와 같은 컨텍스트의 형태로 맵핑할 수 있는 함수객체
- 고차함수인 map을 적용 할 수 있는 컨테이너 타입
- 모나드는 닫힌 함수객체이다
플랫맵(flatMap) 메서드 활용
// MARK: flatMap 활용
func doubledEven(_ num: Int) -> Int? {
if num.isMultiple(of: 2) {
return num * 2
}
return nil
}
print(Optional(6).flatMap(doubledEven(_:))) //Optional(12)
print(Optional(3).flatMap(doubledEven(_:))) //nil
맵과 플랫맵(컴펙트맵)의 차이점
/* map과 flatMap의 차이 */
// 플랫맵(컴팩트맵)은 컨텍스트 내부의 컨텍스트를 모두 같은 위상으로 평평하게 펼쳐준다
let optionals: [Int?] = [1, 2, nil, 5]
let mapped: [Int?] = optionals.map{ $0 } //[Optional(1), Optional(2), nil, Optional(5)]
let flatmapped: [Int] = optionals.compactMap{ $0 } //[1, 2, 5]
print(mapped) //결과를 다시 Array 컨테이너에 담는다
print(flatmapped) //내부 컨테이너까지 값을 추출한다