일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- PushNotification
- 스위프트
- git사용법
- APNS
- UIViewController
- 정규표현식
- flowchart
- 플로우차트
- 백준
- Regex
- 순서도
- swift
- ios
- github란
- flow chart
- github
- JSONSerialization
- 정규식
- GitvsGithub
- Git과 Github차이점
- 애플
- 깃허브
- 플로우 차트
- 흐름도
- git이란
- 계산기
- xcode
- git
- OS
- 깃
- Today
- Total
Diana의 iOS 개발일기
[스위프트 프로그래밍 3판] - 16. 모나드 본문
모나드는 디자인 패턴 중 하나로 스위프트의 함수형 프로그래밍에 대한 이해를 위해서 모나드의 개념을 알아두면 꽤나 도움이 됩니다.
개인적으로는 굉장히 헷갈렸던 부분이라 설명에 오류가 있을 수 있습니다.
[모나드 - Monad]
모나드는 함수와 더불어 순서가 있는 연산을 처리할 때 자주 활용되는 디자인패턴 혹은 자료구조입니다.
프로그래밍에서 모나드는 아래 세 가지 조건을 모두 충족시켜야 합니다.
- 타입을 인자로 받는 타입(특정 타입의 값을 포장)
- 특정 타입의 값을 포장한 것을 반환하는 함수(메서드)가 존재
- 포장된 값을 변환하여 같은 형태로 포장하는 함수(메서드)가 존재
1. 컨텍스트(Context)
컨텍스트는 콘텐츠(Contents)를 담은 그 무언가 라는 의미입니다. 하나의 상자 정도로 이해하면 쉬울 듯 합니다.
옵셔널을 예로 들어보겠습니다.
옵셔널은 특정 값에 대해 값이 없을 수 있음을 나타냅니다.
여기서 더 자세히, 옵셔널의 구성에 대해 알아보자면 옵셔널은 열거형 case로 구현되어 있으며 옵셔널에 값이 없다면 열거형의 .none case로, 값이 있다면 .some(value) case로 값을 가지게 됩니다.
이때 .none case와 .some(value) case를 각각의 상자로 생각하여 옵셔널의 값을 추출에 대해 알아본다면, 옵셔널 값의 추출은 .some(value) case 상자 안의 값을 가져오는 것과 같습니다. 그럼 .none case의 상자 안에는? 아무것도 없는게 되겠죠.
이때 상자로 비유한 .none case와 .some(value) case는 컨텍스트(Context)이며 그 내부의 값은 컨텐츠(Content)라고 합니다.
옵셔널은 위의 설명을 통해 Wrapped 타입을 인자로 받는 (제네릭)타입임을 알 수 있었습니다.
그럼 모나드로서의 첫 번째 조건은 만족한게 되네요.
그럼 두 번째 조건에 대해 이야기 해보자면, 옵셔널은 Optional<Int>.init(2) 처럼 본인은 열거형을 띄고 있으나 결과로 다른 타입(Int)를 갖는 값의 컨텍스트를 생성할 수 있습니다. 두 번째 조건이 만족이 되었죠?
마지막으로 세 번째 조건은 아래 예제를 참고하겠습니다.
func addThree(_ num: Int) -> Int {
return num + 3
}
위의 예제를 보면 addThree( _ : )의 함수는 전달인자로 컨텍스트에 들어가있지 않은 순수 값인 2를 전달받게 되면 Int 타입의 값을 변환하며 정상적으로 작동합니다. 하지만 해당 함수에 옵셔널을 전달인자로 사용하게 될 경우, addThree라는 함수는 순수값 Int를 반환하는 형태인데 컨텍스트 값을 전달받게 되므로 에러가 발생하게 됩니다.
addThree(Optional(2)) //에러!!
컨텍스트를 전달받으려면 컨텍스트로 반환해야한다는 간단한 의미입니다.
2. 함수 객체(Functor)
옵셔널은 위에서도 설명했듯이 컨테이너와 값을 가지고 있으며 맵은 컨테이너를 변형시킬 수 있는 고차함수입니다.
함수 객체 설명을 위해 맵이 필요하므로 우선 예제를 진행해보도록 하겠습니다.
Optional(2).map(addThree) //Optional(5)
어? addThree함수는 순수 Int 값을 전달 받아 다시 순수 Int 값을 반환하는 함수라고 위에서 보았는데 이렇게 맵을 사용하면 Optional 연산이 가능함을 알 수 있습니다.
var value: Int? = 2
value.map{ $0 + 3 } //Optional(5)
value = nil
value.map{ $0 + 3 } // Optional<Int>.none
이렇게 따로 함수 없이 클로저만으로도 사용할 수 있죠.
위의 예제에서는 map은 함수 addThree( _ : )를 인자로 받았고 이후 함수객체에 전달받은 함수를 적용한 뒤( Optional(2) ), 새로운 함수객체( Optional(5) )를 반환합니다. 포장된 값을 연산하여 다시 같은 형태로 포장되었죠?
여기서, 함수객체의 설명에 맵을 언급한 이유를 알아보자면 '함수객체란 맵을 적용할 수 있는 컨테이너 타입'이기 때문입니다.
즉, Array, Dictionary, Set 등의 컬렉션 타입들은 함수객체입니다.
extension Optional {
func map<U>(f: (Wrapped) -> U) -> U? {
switch self {
case .some(let x): return f(x)
case .none: return .none
}
}
}
옵셔널의 map( _ : ) 메서드를 호출하면 옵셔널 스스로 값이 있는지 없는지 switch 구문으로 판단하며 값이 있다면 전달 받은 함수에 자신의 값을 적용한 결괏값을 다시 컨텍스트에 넣어 반환하고, 그렇지 않다면 함수를 실행하지 않고 빈 컨텍스트를 반환합니다.
3. 모나드(Monad)
모나드는 함수객체 중 자신의 컨텍스트와 같은 컨텍스트의 형태로 맵핑할 수 있는 것을 의미합니다.
이때 사용되는 맵핑을 플랫맵(flatMap)이라고 부르고 스위프트 5 버전부터는 compactMap( _ : )이라는 이름을 사용하며 예제는 아래와 같습니다.
func doubledEven(_ num: Int) -> Int? {
if num.isMultiple(of: 2) {
return num * 2
}
return nil
}
Optional(3).flatMap(doubledEven)
// nil ( == Optional<Int>.none)
위의 예제를 보면 결과 값은 nil로 일반 map을 사용했을 때와 차이점이 없어보입니다.
따라서 아래 예제를 통해 두 매핑의 차이점을 알아보겠습니다.
let optionals: [Int?] = [1, 2, nil, 5]
let mapped: [Int?] = optionals.map{ $0 }
let compactMapped: [Int] = optionals.compactMap{ $0 }
print(mapped) // [Optional(1), Optional(2), nil, Optional(5)]
print(compactMapped) // [1, 2, 5]
이 경우를 보면 map의 경우는 Array 컨테이너 내부 값 타입이나 형태가 어찌 되었든, Array 내부에 값이 있으면 그 값을 그저 클로저의 코드에서만 실행하고, 결과를 다시 Array 컨테이너에 담기만 합니다.
하지만 플랫맵의 경우는 클로저를 실행하면 알아서 내부 컨테이너까지 값을 추출합니다. 따라서 mapped는 다시 [Int?] 타입이 되며 compactedMapped는 [Int] 타입이 됩니다.
유튜브: 함수형 프로그래밍이 뭔가요?
www.youtube.com/watch?v=jVG5jvOzu9Y
해당 글은 야곰님의 스위프트 프로그래밍 3판 을 기반으로 한 정리 글이며 문제가 있을 시 삭제하도록 하겠습니다.
스위프트 프로그래밍 3판 eBook 구매 링크: www.yes24.com/Product/Goods/81530016
야곰 님의 블로그: blog.yagom.net
'Swift > 책 정리' 카테고리의 다른 글
[스위프트 프로그래밍 3판] - 18. 상속 (0) | 2021.03.29 |
---|---|
[스위프트 프로그래밍 3판] - 17. 서브스크립트 (0) | 2021.03.22 |
[스위프트 프로그래밍 3판] - 15. 맵, 필터, 리듀스 (0) | 2021.03.18 |
[스위프트 프로그래밍 3판] - 14. 옵셔널 체이닝과 빠른 종료 (1) | 2021.03.17 |
[스위프트 프로그래밍 3판] - 13. 클로저 (0) | 2021.03.11 |