모노이드는 다음 두 가지의 특징을 만족하는 집합을 의미한다.
항등원이란 어떤 함수 f에 대해 f(x,y) === y
일 때, x는 연산 f에 대해 항등원이라고 하며, 수식이 아닌 말로 풀어쓰자면, 어떤 연산자에 대해 적용된 두 개의 피연산자 중 다른 한개의 피연산자를 그대로 반환시켜주는 피연산자를 의미한다.
항등원은 영어로 identity element라고 한다.
연관 바이너리 함수는 다음과 같이 두 피연산자에 대한 연산의 순서가 변경되어도 동일한 값을 반환하는 연산을 의미한다.
연관 바이너리 함수는 영어로 associative binary operation라고 한다.
여기서 바이너리 함수는 bitwise 연산이 아니라, 두 인자를 가지고 다른 인자를 반환하는 연산을 의미한다
집합 S와 binary operaton X 가 있다고 할 때, S X S -> S 일 때
S와 X는 모노이드라고 이야기 하며,
보다 간단하게 모노이드를 정의하면 다음과 같다.
- ⊗ binary 연산에 대해 결합 법칙을 만족하며
(결합 법칙이다. 교환법칙이 아니다.)
- ⊗ binary 연산에 대해 항등원 I가 존재 할 때
항등원 I와 연산 ⊗를 가지고 있는 집합 S는모노이드
이다.
더하기 연산 '+'는 associative binary operator이다.
더하기에 연산 '+'에 대해 항등원 0이 존재한다.
숫자 집합은 (+,0) 라는 모노이드를 가진다.
String.prototype.concat
은 associatve binary operation 이다.
String.prototype.concat
은 항등원 ""
를 가진다.
String Concatenation은 모노이드를 가지고 있다.
object literal를 이용해 Monoid 객체를 만들어볼 것이다.
Monoid 객체는 다음 두 메소드를 가진다.
var Sum = { empty: () => 0, concat: (x, y) => x + y }
Sum.concat(Sum.empty(), 1);
단테의 코틀린 컬렉션 글을 보면 fold 함수를 사용해서 리스트를 줄이는 것을 볼 수 있는데, 모노이드는 이렇게 어떤 컬렉션을 폴딩하는데 사용한다.
자바스크립트의 Array.prototype.reduce
와 함께 사용해보자
우선 앞서 만들었던 Sum Monoid 객체를 클래스로 만들어보자.
class Sum {
empty() {
return 0
}
concat(x,y) {
return x + y
}
}
Sum 객체를 이용해 다른 인스턴스를 만들 수 있을까?
object literal로 만들어 사용할 수 있는 걸 봐서는 굳이 Sum 클래스를 가지고 다른 인스턴스를 만들 필요가 없을 것 같다.
여기서 말하는 인스턴스는 상속을 의미하지 const sum = new Sum()
과 같은 것을 말하는 것이 아니다.
// Sum.js
const Sum = (() => new class Sum {
empty() {
return 0
}
concat(x,y) {
return (x,y) => x + y
}
}())
export default Sum;
const reduced = [1,2,3,4,5,6].reduce(Sum.concat, Sum.empty());