And Brain said,
함수적인, 너무나 함수적인 - 3. 모노이드(Monoid) 본문
Index
0. 함수형 프로그래밍
1. 람다 대수 (Lambda Calculus)와 합성함수
2. 범주론 (Category Theory)
3. 모노이드 (Monoide)
4. 펑터 (Functor)와 엔도펑터(Endo Functor)
5. 모나드 (Monad)
6 함수형 프로그래밍의 고급 기법
두려워 마세요. 모노이드는 당신을 해치지 않습니다. 모노이드는 우리에게 범주론에서 배운 개념들을 구체적으로 적용할 수 있는 좋은 예시가 될 것입니다.
모노이드 (Monoide)
"Monoid"라는 단어는 그리스어에서 유래되었습니다. 그리스어에서 "mono"는 '하나', '단일'을 의미하고, "-oid" 접미사는 '형태' 또는 '종류'를 의미합니다. 따라서 "monoid"는 "단일 형태"나 "단일 종류"라는 의미로 해석할 수 있습니다.
앞서 우리는 범주에 대해서 배워보았습니다. 다시 한 번 범주의 정의를 상기해봅시다.
범주란, 대상과 사상의 모음이다.
이를 바탕으로, 모노이드를 설명하면, 모노이드는 다음의 세 가지 조건을 만족하는 대상과 사상에 관한 개념입니다.
(대상) 집합 (Set): 원소들의 모음. 예를 들어, 정수 집합, 문자열 집합 등이 있습니다.
(사상) 이항 연산 (Binary operation): 두 원소를 입력받아 집합의 다른 원소를 반환하는 연산입니다. 이 연산은 해당 집합 내에서만 이루어집니다. 이항 연산은 함수 f: S × S → S와 같이 정의됩니다. 대표적인 이항 연산으로 덧셈, 곱셈, 나눗셈 등이 있습니다.
(사상으로서 만족해야 하는 요구 사항들)
결합법칙 (Associativity): 모든 원소 a, b, c에 대해 (a · b) · c = a · (b · c)가 성립해야 합니다. 즉, 연산의 순서가 결과에 영향을 주지 않습니다. 예를 들어, 정수의 덧셈 연산은 결합 법칙이 성립합니다. (1 + 2) + 3 = 1 + (2 + 3) = 6입니다.
항등원 (Identity element): 항등원은 이항 연산에서 특별한 역할을 하는 원소로, 집합 S의 모든 원소 a와 연산을 수행할 때 결과가 a 자신이 되는 원소를 의미합니다. 즉, 집합 S의 원소 e에 대해 e · a = a · e = a가 성립해야 합니다. 예를 들어, 정수의 덧셈 연산에서 항등원은 0이며, 곱셈 연산에서는 1입니다. 0 + 3 = 3 + 0 = 3이고, 1 * 3 = 3 * 1 = 3입니다.
즉, 모노이드도 대상(집합)과 사상(이항 연산)으로 구성되어 있습니다. 이러한 단일 형태의 대수 구조라는 의미에서 모노이드라는 이름이 붙여졌습니다. 그렇다면 이 모노이드를 함수형 프로그래머가 왜 알아야 하는걸까요?
모노이드는 함수형 프로그래밍에서 다음의 몇 가지 주요 원칙과 잘 어울립니다.
합성 가능성(Composability): 모노이드는 결합법칙이 성립하기 때문에, 순서에 상관없이 작은 단위의 연산을 조합하여 더 큰 연산을 구성할 수 있습니다. 이렇게 작은 단위의 함수를 조합하여 복잡한 문제를 해결하는 것이 함수형 프로그래밍의 핵심입니다.
불변성(Immutability): 모노이드는 불변성과 관련이 깊습니다. 모노이드 연산은 새로운 값을 생성하기 때문에 기존의 값을 변경하지 않습니다. 이는 함수형 프로그래밍에서 중요한 불변성 원칙과 일치합니다.
추상화(Abstraction): 모노이드는 다양한 자료구조와 알고리즘에 일반화될 수 있는 추상적인 개념입니다. 이를 통해 모노이드를 사용하는 코드는 더 간결하고 일반적인 형태를 갖게 되며, 재사용성이 높아집니다.
병렬 처리(Parallelism): 모노이드는 결합법칙을 만족하므로, 병렬 처리에 유리합니다. 연산 순서가 중요하지 않기 때문에, 여러 서브태스크로 쪼개어 동시에 실행하고 그 결과를 다시 결합할 수 있습니다. 이는 함수형 프로그래밍에서 병렬 처리를 쉽게 구현할 수 있는 기반을 제공합니다.
// 모노이드 인터페이스를 정의합니다.
interface Monoid<T> {
// 항등원: 이항 연산에서 어떤 값과 연산했을 때 그대로 반환되는 값을 의미합니다.
empty: () => T;
// 이항 연산: 두 개의 값을 결합하는 함수입니다. 결합법칙이 성립해야 합니다.
// (a ⊕ b) ⊕ c = a ⊕ (b ⊕ c)
concat: (a: T, b: T) => T;
}
// 문자열 모노이드의 예입니다.
const stringMonoid: Monoid<string> = {
empty: () => "", // 항등원: 빈 문자열
concat: (a: string, b: string) => a + b, // 이항 연산: 문자열 결합
};
// 숫자 합 모노이드.
const sumMonoid: Monoid<number> = {
empty: () => 0, // 항등원: 0
concat: (a: number, b: number) => a + b, // 이항 연산: 숫자 합산
};
// 숫자 곱셈 모노이드.
const productMonoid: Monoid<number> = {
empty: () => 1, // 항등원: 1
concat: (a: number, b: number) => a * b, // 이항 연산: 숫자 곱셈
};
// 배열 모노이드.
// 제네릭 함수를 사용하여 다양한 타입의 배열 모노이드를 생성할 수 있습니다.
const arrayMonoid = <T>(): Monoid<T[]> => ({
empty: () => [], // 항등원: 빈 배열
concat: (a: T[], b: T[]) => a.concat(b), // 이항 연산: 배열 병합
});
이렇게 모노이드를 사용하면, 다양한 문제를 추상화하여 일반적인 형태로 해결할 수 있으며, 재사용 가능한 코드를 작성할 수 있습니다. 그러면, 구체적으로 이 모노이드를 사용해봅시다.
// fold 함수를 이용하여 주어진 배열을 모노이드 연산으로 축약합니다.
// 이 함수는 재사용 가능하며, 다양한 모노이드 인스턴스를 사용할 수 있습니다.
function fold<T>(monoid: Monoid<T>, values: T[]): T {
return values.reduce((acc, val) => monoid.concat(acc, val), monoid.empty());
}
// 문자열 모노이드를 이용하여 문자열 배열을 결합합니다.
const strings = ["Hello", " ", "world", "!"];
const combinedString = fold(stringMonoid, strings);
console.log(combinedString); // 출력: "Hello world!"
// 숫자 합 모노이드를 이용하여 숫자 배열의 합을 구합니다.
const numbers = [1, 2, 3, 4, 5];
const sum = fold(sumMonoid, numbers);
console.log(sum); // 출력: 15
// 숫자 곱셈 모노이드를 이용하여 숫자 배열의 곱을 구합니다.
const product = fold(productMonoid, numbers);
console.log(product); // 출력: 120
// 배열 모노이드를 이용하여 배열들을 병합합니다.
const arrays = [
[1, 2],
[3, 4],
[5, 6],
];
const combinedArray = fold(arrayMonoid<number>(), arrays);
console.log(combinedArray); // 출력: [1, 2, 3, 4, 5, 6]
이렇게 fold 함수를 이용하여 서로 다른 모노이드 연산을 수행할 수 있습니다. 이 모노이드를 활용한다면 함수형 프로그래밍이 무궁무진하게 확장할 수 있다는 느낌이 오시지 않나요?
정리해봅시다. 모노이드는 하나의 집합에 이항 연산이 정의되어 있고, 그 연산이 결합법칙을 만족하며 항등원이 존재하는 대수 구조로, 함수형 프로그래밍에서 합성 가능성, 불변성, 추상화 및 병렬 처리와 같은 특성을 지원합니다. 자, 그러면 다음은 펑터(Functor)로 넘어가봅시다.
Thanks for watching, Have a nice day.
References
https://dev.to/ingun37/monad-monoid-40if
https://kpug.github.io/fp-gitbook/Chapter3.html
https://itchallenger.tistory.com/513
'IT > 함수적인, 너무나 함수적인' 카테고리의 다른 글
함수적인, 너무나 함수적인 - 5. 모나드(Monad) (4) | 2023.05.01 |
---|---|
함수적인, 너무나 함수적인 - 4. 펑터 (Functor)와 엔도펑터(Endo Functor) (4) | 2023.04.22 |
함수적인, 너무나 함수적인 - 2. 범주론 (Category Theory) (0) | 2023.04.16 |
함수적인, 너무나 함수적인 - 1. 람다 대수 (Lambda Calculus)와 합성 함수 (0) | 2023.04.16 |
함수적인, 너무나 함수적인 - 0. 함수형 프로그래밍 (0) | 2023.04.16 |