
Functor란 무엇인가?
struct Stack<T> {
private var items: [T] = []
mutating func push(_ item: T) {
items.append(item)
}
mutating func pop() -> T? {
return items.popLast()
}
func peek() -> T? {
return items.last
}
var isEmpty: Bool {
return items.isEmpty
}
var count: Int {
return items.count
}
}
// Int 타입의 스택 생성
var intStack = Stack<Int>()
intStack.push(1)
intStack.push(2)
intStack.push(3)
OptionalArrayDictionarySetResultEitherFuturePromiseOptional<T>Array<T>Dictionary<T, U>Set<T>Result<T, E>Either<T, U>Future<T>Promise<T>Stack<T>이라는 타입을 Generic으로 만들고 값을 감쌀 수 있다면 이는 Type Constructor이다.Functor: 임의의 타입
T, U가 주어졌을 때, 연산 lift이 정의되는 Type ConstructorFlift:
(T -> U) -> (F(<T>) -> F(<U>))
T->U인 함수가 있을 때, 각각의 원소를 Type Constructor F로 감싸는 함수로 변환할 수 있으면 Functor(T->U)로 가는 건 내부에 들어간 값을 변형 하는 것이다. 이제부터 이걸 transform이라 부르겠다.internal func lift<T, U>(_ transform: @escaping (T) -> U) -> (Optional<T>) -> Optional<U> {
return { (input: Optional<T>) -> Optional<U> in
switch input {
case .none:
return .none
case .some(let wrapped):
return .some(transform(wrapped))
}
}
}
transform을 인자로 받아 Optional<T>를 인자로 받아 Optional<U>를 반환하는 함수를 반환한다.Optional은 Functor이다.internal func lift<T, U>(_ transform: @escaping (T) -> U) -> ([T]) -> [U] {
return { (input: [T]) -> [U] in
var result: [U] = []
for index in input.indices {
result.append(transform(input[index]))
}
return result
}
}
internal func lift<T, U>(_ transform: @escaping (T) -> U) -> (Result<T, Error>) -> Result<U, Error> {
return { (input: Result<T, Error>) -> Result<U, Error> in
switch input {
case .failure(let error):
return .failure(error)
case .success(let value):
return .success(transform(value))
}
}
}
<T, U>를 직접 선언해두지 않고, 타입 내에서 결과 타입만 가지고 있을 수 있게 안에서 구현한다.Array, Set과 같이 Sequence로 묶이는 경우에는 상위 타입의 프로토콜이나 클래스에서 구현해둔다.internal enum Optional<Wrapped> {
case none
case some(Wrapped)
func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> U? {
switch self {
case .none:
return .none
case .some(let wrapped):
return try .some(transform(wrapped))
}
}
}
lift라 구현 안되어 있고 map으로 되어 있다.Optional, Array, Result는 Functor이다.Functor라는 프로토콜을 만들든, 클래스를 만들든 한 다음에 이걸 상속하게 해서 기본 동작을 제공할 것이다.
Set, Array같은 경우는 Sequence Protocol을 상속받아 처리되고,Optional의 경우에는 자체적으로 가지고 있다.T->U로 가는 함수를 받아 F(T)를 받아 F(U)를 반환하는 함수를 반환한다.id_T = (T -> T)
id_F<T> = (F(T) -> F(T))
lift = (X -> Y) -> (F<X> -> F<Y>)
lift(id_T) = id_F<T>
T->T인 항등함수는 id_T라고 표현할 수 있다.F(T)->F(T)인 항등함수는 id_F<T>라고 표현할 수 있다.(X -> Y) -> (F<X> -> F<Y>) 라고 표현할 수 있는데, 이 연산의 결과는 뭐가 나올지 모른다.f = (T -> U)
g = (U -> V)
lift = (X -> Y) -> (F<X> -> F<Y>)
h = g∘f
lift(h) = lift(g∘f) = lift(g)∘lift(f)
즉,
lift(g∘f) = lift(g)∘lift(f)
h가 g와 f의 합성이라고 한다면,h를 lift한 결과 역시 g와 f를 lift한 결과의 합성과 같다. (lift(g)∘lift(f))func f(_ x: Int) -> Int {
return x + 1
}
func g(_ x: Int) -> Int {
return x * 2
}
func h(_ x: Int) -> Int {
return g(f(x))
}
let optional = Optional.some(10)
let result1 = lift({ h($0) })(optional) // Optional.some(22)
let result2 = lift({ g($0) })(lift({ f($0) })(optional)) // Optional.some(22)
let array = [3, 4, 5, 6]
let result1 = lift({ h($0) })(array) // [8, 10, 12, 14]
let result2 = lift({ g($0) })(lift({ f($0) })(array)) // [8, 10, 12, 14]
let result: Result<Int, Error> = .success(10)
let result1 = lift({ h($0) })(result) // success(22)
let result2 = lift({ g($0) })(lift({ f($0) })(result)) // success(22)