도니의 iOS 프로그래밍 세상

[Swift] flatMap, map의 차이 - Monad로의 여정(1) 본문

Swift

[Swift] flatMap, map의 차이 - Monad로의 여정(1)

Donee 2023. 12. 15. 23:12

함수형 프로그래밍에서 사용되는 말인 Monad에 대해서 설명하기 전, map 과 flatMap 의 차이점에 대해서 공부해보자

map과 flatMap은 차이점은 무엇일까?

가장 기본적인 차이점

  1. map의 경우 데이터를 변환하는데 사용된다
let cast = ["Vivien", "Marlon", "Kim", "Karl"]
let lowercaseNames = cast.map { $0.lowercased() }
// 'lowercaseNames' == ["vivien", "marlon", "kim", "karl"]
  1. flatMap은 2차원 이상의 배열들을 1차원 배열로 변환한다
let numbers = [1, 2, 3, 4]

let mapped = numbers.map { Array(repeating: $0, count: $0) }
// [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4]]

let flatMapped = numbers.flatMap { Array(repeating: $0, count: $0) }
// [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]

진정한 차이점

Optional 에서 map 만 사용해선, 우리는 함수 체이닝을 가독성이 좋은 구조로 구현할 수 없다.

이를 위해서, 우리는 필요한 상황에서 flatMap 을 사용해야 한다

실제 예시를 보면서 해당 의의를 이해하는것이 더 편하다

1. Optional에 map을 사용한 예시

let optString: String? = "33"
let result = optString.map { "3" + $0 }

// result의 타입은 String?, 값은 "333"
  • 위의 경우, optString의 값이 nil이라면 nil이 리턴되고, nil이 아니라면 “333”이 리턴된다
  • 기존에 guard let, if let등으로 불필요하게 값의 유무를 확인해서 벗기지 않아도 된다

하지만, 밑의 경우는 어떠할까?

let optString: String? = "33"
let result = optString.map { Int($0) }
// result 타입은 Int??, 값은 33 
  • Int 생성자에 string을 넣으면, Int(string: String) -> Optional(Int)이다.
  • 결국, Int($0)의 리턴 타입은 Optional(Int)이다.
  • 따라서, map 의 리턴 타입이 Int?? 이다.
  • 만약 이럴때, map을 통해서 체이닝 하는것은 굉장히 번거로워진다.(Optional이 이중으로 wrapping된 상태이기에)
  • 이때는 flatMap 을 사용한다
  • 2. Optional에 flatMap을 사용한 예시
let optString: String? = "33"
let result = optString.flatMap { Int($0) }
// result 타입은 Int?, 값은 33
  • flatMap을 통해 다음과 같이 Optional(Int) 를 리턴 받는다
  • 이를통해, 우리는 map이나 flatMap을 통해 함수 체이닝을 구현할 수 있게 되었다

2. 두 함수 구현의 차이점

Optional 타입에서 map, flatMap의 정의는 다음과 같다.

func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> U?

func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U?
  • map의 경우, transform 의 리턴 타입인 U에 Optional인 Optional(U) 를 리턴하는 구조이다.
  • flatMap의 경우 transform 의 리턴 타입이, Optional(U) 이고, 리턴 타입또한 Optional(U) 이다.

이전 예시를 통해 그림으로 살펴보면 다음과 같다.(알파벳 맞추기와 동일하다)

  • map은 transform 의 리턴 타입인 U 의 Optional 타입인 Optional(U) 를 리턴한다
  • flatMap은 transform 의 리턴 타입인 Optional(U) 를 그대로 리턴한다.

결국, map은 transform 의 리턴 타입이 Optional 이 아닌 경우에 사용해야 한다.

flatMap은 transform 의 리턴 타입이 Optional 인 경우 사용한다.

이둘을 적절하게 사용할때, 우린 함수 체이닝을 가능하게 한다.

이들을 알아야 Monad 가 무엇인지 이해할 수 있다

결론

  1. map 과 flatMap 의 기본적인 차이는, array를 평탄화 시키거나, 값을 변경할때 사용된다.
  2. map, flatMap 의 적절한 사용은 함수 체이닝 을 가능하게 한다
  3. 이들은 Monad 를 이해하는데 필요한 요구 사항이다.

참조

https://developer.apple.com/documentation/swift/sequence/map(_:)

https://developer.apple.com/documentation/swift/sequence/flatmap(_:)

https://developer.apple.com/documentation/swift/optional/map(_:)

https://developer.apple.com/documentation/swift/optional/flatmap(_:)

Comments