Motive
- 프로젝트가 너무 바쁘다 보니 개념을 정립하고 싶어서 주말에 공부하다가, 예전에 처음 Swift를 공부할 때 빠르게 한 번 보고 지나간 모나드를 공부하기로 했다.
- RealmDB에서 가져온 값이 대부분 Result? 타입으로 가져오는데 무지성으로 CompactMap을 쓰는 게 싫어서 공부를 하려고 했으나 시간이 잘 나지 않았다.
Context
- Context는 지금껏 프로그래밍을 하면서 많이 봐왔지만, 개념을 정리하는 것은 이번이 처음인 것 같다.
- 컨텍스트는 'Contents'를 담은 그 무엇인가를 뜻한다.
- 담배각에 안에 담배가 있다면 담배가 컨텐츠이고, 담배각은 컨텍스트이다.
Optional As An Example
- 많은 서적과 블로그 자료들을 찾아보면 대부분 예를 들을 때, Optional을 예로 든다. 그 이유는 Optional이 아마 예를 만들기 가장 쉬운 Monad이기 때문인 것 같다.
- Optional을 Wrapped 타입을 인자로 받는 (제네릭)타입이다.
- 즉, 타입을 인자로 받는 모나드의 첫 번째 조건을 만족하고
- Optional<
Int
>.init(2)은 다른 타입의 형태를 만들 수 있기 때문에 두 번째 조건을 만족한다.
- 세 번째 조건은 내 개인적으로는 .map 메서드가 사용이 가능하면 세 번째 조건은 달성된다고 생각하는데 자세한 설명은 아래에서 하겠다.
Example
Optional(2)
- 상기와 같이 2라는 숫자를 옵셔널로 감싸면, Context 안에 2라는 Contents가 들어간다고 생각하면 된다.
- 만약 값이 있다면 '컨텍스트는 2라는 값을 가지고 있다'
- 만약 값이 없다면 '컨텍스트는 있는데 값이 없다' 라고 할 수 있다.
func addThree(_ num: Int) -> Int {
return num +3
}
- 상기의 메서드에는 Optional(2)를 인자로 전달해도 정상적인 동작을 하지 않는다.
- 당연히 인자의 타입이 Int로 선언 되어 있기도 하지만, 컨텍스트에 둘러 쌓여 있는 값에 +3을 할 수 없는 것이다.
functor
- 한국말로는 함수객체라고 한다
- 함수객체란 맵을 적용할 수 있는 컨테이너 타입이다.
- 우리가 사용하는 Array, Dictionary, Set 등 Swift의 많은 컬렉션 타입이 함수객체이다.
- map은 컨테이너 내부의 값을 변형시킬 수 있는 고차함수이다.
- 그럼 아까의 addThree를 맵을 사용해 적용해보겠다.
Optional(2).map(addThree)
var exampleValue : Int? = 2
exampleValue.map {$0 + 3}
Monad
- 함수객체 중에서 자신의 컨텍스트와 같은 컨텍스트의 형태로 맵핑할 수 있는 함수객체를 닫힌 함수 객체라고 한다. 모나드는 닫힌 함수객체이다.
- 즉, Map을 적용할 수 있는 컨테이너이고, 자신의 컨텍스트와 같은 형태로 맵핑할 수 있는 닫힌 함수 객체로 정의할 수 있다.
- 함수객체는 포장된 값에 함수를 적용할 수 있다.
- 모나드도 포장된 값을 처리하고 포장된 값을 컨텍스트에 다시 반환하는 함수(맵)을 적용 가능하다.
- 이 mapping의 결과가 함수객체와 똑같은 컨텍스트를 반환하는 함수객체를 모나드라고 할 수 있고, 이런 맵핑을 수행하도록 flatMap이라는 메서드를 활용한다.
Condition of Monad
- 타입을 인자로 받는 타입(특정 타입의 값을 포장)
- 특정 타입의 값을 포장한 것을 반환하는 메서드가 존재
- 포장된 값을 변환하여 같은 형태로 포장하는 메서드가 존재
flatMap
Review
- 한 번은 개념적으로 공부하고 넘어가고 싶었다.
- 한 번 봐서 끝낼 개념이 아니고 일을 하면서 좀 더 주변 지식이 쌓이면 그 때 마다 다시 보면 또 다르고 넓게 보일 개념같다.
- 최근 함수형 프로그래밍에 관심이 생기면서 개념을 탄탄하게 하기 위해 개념을 정리한다.
- 최근 기본서를 다시 보면서 모르는 부분을 골라서 읽고 있는데 추후에도 기본 개념들을 정리해 나갈 생각이다.