fp-tsとMonoid
Kazuki Moriyama (森山 和樹)
単位元付きの二項演算を司る型クラスMonoidを紹介。
https://gcanti.github.io/fp-ts/modules/Monoid.ts.html
定義
interface Monoid<A> extends Semigroup<A> {
readonly empty: A
}
定義を見ると分かる通り、すべてのMonoidはSemigroupである。
参考: Semigroupについて。
できるのはなにか2つをとって一つを返すこと。
そして単位元がそれにひっついていること。
満たすべきlaw
concatについてはSemigroupと同様に結合律を満たす必要がある。
更にemptyについては以下のように単位元にならなければならない。
concat(x, empty) = concat(empty, x) = x
使い方
import * as S from "fp-ts/string";
import * as N from "fp-ts/number";
console.log(S.Monoid.concat("a", "b")); // => ab
console.log(N.MonoidSum.concat(2, 3)); // => 5
console.log(N.MonoidProduct.concat(2, 3)); // => 6
console.log(N.MonoidProduct.empty); // => 1
console.log(N.MonoidSum.empty); // => 0
numberに対しては和と積で作られたMonoidが用意されている。
単位元もそれぞれ異なる。
combinators
reverse
引数を入れ替えてconcatに適用するMonoidを返す。
console.log(Monoid.reverse(S.Monoid).concat("a", "b")); // => ba
struct
オブジェクトに対するMonoidを複数のMonoidから構築できる。
type Person = {
name: string;
age: number;
};
const personMonoid = Monoid.struct<Person>({
name: S.Monoid,
age: N.MonoidSum,
});
console.log(
personMonoid.concat({ name: "tanaka", age: 20 }, { name: "taro", age: 10 })
); // => { name: 'tanakataro', age: 30 }
tuple
タプルのMonoidを複数のMonoidから構築できる。
const tuple3Monoid = Monoid.tuple(S.Monoid, N.MonoidSum, N.MonoidProduct);
console.log(tuple3Monoid.concat(["a", 2, 3], ["b", 4, 5])); // => [ 'ab', 6, 15 ]
constructors
max/min
Bounded<A>というある型Aにたいする上限値と下限値を定義する型クラスをとってAのMonoidインスタンスを作成する。
concatのロジックはそれぞれ大きい方、小さい方を返すだけである。
console.log(Monoid.max(N.Bounded).concat(1, 2)); // => 2
console.log(Monoid.min(N.Bounded).concat(1, 2)); // => 1
BoundedはOrdを継承しているため、Ordによる大小比較が内部的には使用されている。
ロジック的にBoundedいらなくね?と思うかもしれないが、max/minが作っているのはあくまでもMonoidであるためempty用の値が必要となる。
empty値としてBoundedの上限値、もしくは下限値が使用されている。
console.log(Monoid.max(N.Bounded).empty); // => -Infinity
console.log(Monoid.min(N.Bounded).empty); // => Infinity
utils
concatAll
Monoidを与えると配列の中身を全部concatしてくれる便利なやつ。
reduceとかの挙動のイメージ。
console.log(Monoid.concatAll(N.MonoidSum)([1, 2, 3])); // => 6