
Monad는 어떻게 정의할 수 있을까?
Monad: 다음의 연산들이 정의된 Functor
unit:
T -> M<T>(returnin Haskell)flat:
M<M<T>> -> M<T>(joinin Haskell)
unit하고 flat추가한게 모나드다.unit, flat이 어떤 조건을 만족해야 하는지는 가장 아래에서 알아보자.unit, flat 함수가 가져야할 추가 조건에 대해 설명한다.
T->U로 가는 함수를 f라고 정의해보자.lift함수에 f를 인자로 넣어서 나오는 반환 값의 타입은 M<T> -> M<U>이다.M<T>를 인자로 넣어서 나오는 반환 값의 타입은 M<U>이다.
f를 적용한 후 unit함수를 적용한 것과unit함수를 통해 M<T>를 M<U>로 바꾸고, f를 적용한 것이 같다는 말이다.naturality for flat.

T->U로 가는 함수를 f라고 정의해보자.lift함수에 f를 인자로 넣어서 나오는 반환 값의 타입은 M<T> -> M<U>이다.M<T>를 위 함수에 넣으면 반환값은 M<U>이다.M<M<T>>를 M<M<U>>로 바꾸려면 lift(lift(f))를 적용해야 한다.
lift(lift(f))를 적용한 후 flat함수를 적용한 것과flat 함수를 적용하고 lift(f)를 적용한 것이 같다는 말이다.
M<T>를 M<M<T>>로 바꾸는 방법은 두개가 있다.unit을 적용하거나, lift(unit)을 적용하거나.unit이라는 함수의 이름이 이 때문인 듯 하다.lift를 여러번 적용했을 때의 함수와 unit을 적용했을 때의 함수가 같다.unit을 적용한다는 것은 M<T> 타입 자체에 함수 동작을 걸어버리는 것이고,lift(unit)을 적용한다는 것은 T타입에 unit함수를 적용한다는 가정을 한 상황에서 lift를 통해 한차원 높인 상태의 함수를 만들고 적용한다고 생각할 수 있겠다.
M<M<T>>에 flat함수를 걸었을 때 결과는 M<T>로 나와야 한다는 것이 항등성이다.
M<M<M<T>>>를 M<M<T>>로 바꾸는 방법은 두개가 있다.flat을 적용하거나, lift(flat)을 적용하거나.

T->U로 보내는 함수들의 집합을 하나 생각해보자.T, U는 제네릭으로 표현되었으니, 하나하나 구체 타입을 넣어보면 원소들이 있는 공간이 떠오를 것이다.M<T>->M<U>로 보내는 함수들의 집합도 생각해보자.Double->String으로 가는 함수 원소의 개수도 엄청많은데, 사실 그 변형 함수 로직의 다양성까지 포함해야한다.
T->U로 가는 함수 원소를 대표할 수 있게 위와 같이 그림을 그려보았다.f와 같은 형태로 변수로 표현했다.lift(f)이다.
Double 자료형은 1.0, -3000과 같은 다양한 실수값을 반영할 수 있는 집합의 개념이다.f라는 변환은 값들이 U의 공간에 특정 점에 매핑된다고 할 수 있다.M<T>->M<U>에 대응되는 원소는 어떻게 그릴 수 있을까?f에 대응되는 녀석)은 무엇이 될 수 있을까?
unit함수의 의미부터 알아보자.unit 함수는 함수를 원소로 갖는 두 집합 사이의 관계를 정의한다.
lift은 어떻게 도식할 수 있을까.T와 U사이에 f라는 논리적 관계가 정의되어 있다면, T와 U를 unit한 값들 사이에서도 lift(f)로 표현되는 논리적 관계가 존재해야 한다.unit이라는 관계는 값들 사이의 논리적 관계를 전부 보존하는 변환이어야 한다.T타입을 모나드화 하는 unit연산의 수행 결과는, T의 의미를 전부 보존해야만 한다.Int을 Double로 바꾸는 연산.M<T>는 T 또는 T와 논리적으로 동등한 개념을 지칭하는 타입이라는 것을 알 수 있다.
flat은 M<M<T>>를 M<T>로 바꿔주는 연산이다.
lift(lift(f))로 표현되었던 연산의 "일부" 논리적 관계는 보존해야 한다.flat이라는 함수는 값의 의미를 적어도 일부는 보존한 채 M<M<T>>를 M<T>로 바꾸는 변환이 되어야 한다.M<T>는 T의 의미를 확장한 의미를 가진 타입이어야 한다. (unit)M<M<T>>는 어떤 의미에서는 M<T>와 같이 간주될 수 있어야 한다. (flat)
T의 의미를 확장한 Optional의 의미는 T 또는 nil이다. 즉, 포함한 채로 확장한 의미이다.Optional<Optional<T>>는 Optional<T>와 같이 간주될 수 있다.T의 의미를 확장한 Array의 의미는 T의 집합이다. 즉, 포함한 채로 확장한 의미이다.Array<Array<T>>는 Array<T>와 같이 간주될 수 있다.모나드는 어떠한 개념에 대한 논리적 확장으로, 오직 한번만 의미있게 적용 가능한 것들을 통칭하는 개념이다.
M이 Monad라면,
T의 의미를 확장할 수 있는 방법이 정의되어 있어야 한다.
flatMap) 구현하는 경우가 많다.extension Optional {
internal func unit(_ t: T) -> T? {
.some(t)
}
}
extension Optional {
internal func flat<T>(_ oot: Optional<Optional<T>>) -> Optional<T> {
switch oot {
case .none:
return .none
case .some(let ot):
return ot
}
}
}
"자연성(naturality)"은 수학에서 함수나 변환자(transformer) 사이의 관계가 다른 수학적인 구조를 변형해도 변환의 특성을 유지하는 것을 의미합니다. 이러한 관계는 수학적인 구조 간에 일관성을 유지하며 변환을 적용할 수 있도록 해줍니다.
예를 들어, 두 개의 함수 F와 G가 있고, 어떤 구조에서 F와 G를 적용할 때 일관성이 유지된다고 가정해봅시다. 그렇다면 이 두 함수 사이의 관계는 "자연성"을 가진다고 할 수 있습니다. 즉, 어떤 변환을 적용하더라도 결과가 일관성 있게 유지되는 것입니다.
모나드(Monad)의 항등성(identity law)은 함수형 프로그래밍에서 모나드가 가져야 하는 중요한 특성 중 하나입니다. 모나드는 데이터 형식을 다루는 추상적인 개념으로, 값을 감싸거나 조작하는 데 사용됩니다. 이 때 모나드의 항등성은 모나드의 동작을 보다 안정적이고 일관적으로 만들어줍니다.
모나드의 항등성은 크게 두 가지 관점에서 설명될 수 있습니다
어떤 값을 모나드로 감싼 후에 해당 모나드를 특정 함수에 적용하는 것과, 그 값을 바로 그 함수에 적용하는 것은 같아야 합니다. 즉, m이라는 모나드와 함수 f가 있다면, 아래와 같은 관계가 성립해야 합니다
flatMap(unit(x), f) == f(x)
여기서 unit(x)는 값을 모나드로 감싸는 역할을 하는 함수입니다. flatMap은 모나드의 값을 함수에 적용하는 연산을 나타내며, f는 임의의 함수를 나타냅니다.
모나드에 값을 적용한 뒤에 모나드를 벗겨낸 결과와, 그 값을 바로 모나드에 감싸지 않은 결과는 같아야 합니다. 즉, m이라는 모나드와 함수 f가 있다면, 아래와 같은 관계가 성립해야 합니다:
flatMap(m, unit) == m
여기서 unit은 값을 모나드로 감싸는 역할을 하는 함수입니다.