fp-ts を使って実現できました。
環境構築
Bun を使いました。
$ bun init
$ bun install fp-ts
失敗例
大統領名の配列から、大統領ごとの在任回数を保持する Map を作ろうとしています。
term_count.ts
const recentPresidents: [string, string][] = [
["Donald", "Trump"],
["Joe", "Biden"],
["Donald", "Trump"],
];
const presidentTermCount = new Map<[string, string], number>();
for (const name of recentPresidents) {
if (presidentTermCount.has(name)) {
presidentTermCount.set(name, presidentTermCount.get(name)! + 1);
} else {
presidentTermCount.set(name, 1);
}
}
console.log(presidentTermCount);
実行結果は以下のようになります。["Donald", "Trump"] の在任回数は 2 であるべきなのに、失敗しています。
$ bun run term_count.ts
Map(3) {
[ "Donald", "Trump" ]: 1,
[ "Joe", "Biden" ]: 1,
[ "Donald", "Trump" ]: 1,
}
成功例
Tuple は Array なので、string[] 用の Eq を使う Map を作ると、うまくいきました。
term_count_fp.ts
import * as A from "fp-ts/Array";
import * as N from "fp-ts/number";
import * as S from "fp-ts/string";
import * as Map from "fp-ts/Map";
const recentPresidents: [string, string][] = [
["Donald", "Trump"],
["Joe", "Biden"],
["Donald", "Trump"],
];
const presidentTermCount = Map.fromFoldable(
A.getEq(S.Eq),
N.SemigroupSum,
A.Foldable
)(recentPresidents.map((name) => [name, 1]));
console.log(presidentTermCount);
実行結果は以下のようになります。
$ bun run term_count_fp.ts
Map(2) {
[ "Donald", "Trump" ]: 2,
[ "Joe", "Biden" ]: 1,
}
所感
実現はできましたが、難しすぎる気がします。生成 AI の助けも借りて何とか実装できましたが、どういう仕組みなのか、同僚が理解できるように説明する自信はありません。
この例だったら、キーを JSON とかスペース区切りの "Donald Trump" のような string にするのが実務的な解決策なのかな? 誰でも理解できるコードになりますよね。
もっと良い方法があったら教えていただきたいです。