Skip to content

Commit

Permalink
feat: Add MultiSet, doMut and monad field on CatT (#200)
Browse files Browse the repository at this point in the history
  • Loading branch information
MikuroXina committed May 11, 2024
1 parent e2b049c commit 136ded7
Show file tree
Hide file tree
Showing 8 changed files with 279 additions and 90 deletions.
1 change: 1 addition & 0 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export * as Kleisli from "./src/kleisli.ts";
export * as Lazy from "./src/lazy.ts";
export * as List from "./src/list.ts";
export * as Map from "./src/map.ts";
export * as MultiSet from "./src/multi-set.ts";
export * as Number from "./src/number.ts";
export * as Optical from "./src/optical.ts";
export * as Option from "./src/option.ts";
Expand Down
22 changes: 10 additions & 12 deletions src/binray-heap.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,21 @@ import {
length,
popMin,
} from "./binary-heap.ts";
import { doT } from "./cat.ts";
import { monad, runMut } from "./mut.ts";
import { doMut } from "./mut.ts";
import { none, some } from "./option.ts";
import { nonNanOrd } from "./type-class/ord.ts";

Deno.test("simple usage", () => {
runMut(<S>() => {
const m = monad<S>();
return doT(m)
doMut((cat) =>
cat
.addM(
"heap",
empty(nonNanOrd),
)
.addMWith("min", ({ heap }) => getMin(heap))
.runWith(({ min }) => {
assertEquals(min, none());
return m.pure([]);
return cat.monad.pure([]);
})
.runWith(({ heap }) => insert(1)(heap))
.runWith(({ heap }) => insert(5)(heap))
Expand All @@ -33,21 +31,21 @@ Deno.test("simple usage", () => {
.runWith(({ min, len }) => {
assertEquals(min, some(1));
assertEquals(len, 3);
return m.pure([]);
return cat.monad.pure([]);
})
.addMWith("popped", ({ heap }) => popMin(heap))
.addMWith("min", ({ heap }) => getMin(heap))
.runWith(({ popped, min }) => {
assertEquals(popped, some(1));
assertEquals(min, some(2));
return m.pure([]);
return cat.monad.pure([]);
})
.addMWith("popped", ({ heap }) => popMin(heap))
.addMWith("min", ({ heap }) => getMin(heap))
.runWith(({ popped, min }) => {
assertEquals(popped, some(2));
assertEquals(min, some(5));
return m.pure([]);
return cat.monad.pure([]);
})
.addMWith("popped", ({ heap }) => popMin(heap))
.addMWith("min", ({ heap }) => getMin(heap))
Expand All @@ -56,7 +54,7 @@ Deno.test("simple usage", () => {
assertEquals(popped, some(5));
assertEquals(min, none());
assertEquals(wasEmpty, true);
return m.pure([]);
}).finish(() => {});
});
return cat.monad.pure([]);
}).finish(() => {})
);
});
6 changes: 6 additions & 0 deletions src/cat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ export interface CatT<M, CTX> {
*/
readonly ctx: Get1<M, CTX>;

/**
* The `Monad` instance for `M`.
*/
readonly monad: Monad<M>;

/**
* Binds a new value wrapped by the monad.
*
Expand Down Expand Up @@ -169,6 +174,7 @@ export interface CatT<M, CTX> {
export const catT =
<M>(monad: Monad<M>) => <CTX>(ctx: Get1<M, CTX>): CatT<M, CTX> => ({
ctx,
monad,
addM: <const K extends PropertyKey, A>(key: K, value: Get1<M, A>) =>
catT(monad)(
monad.flatMap((c: CTX) =>
Expand Down
108 changes: 51 additions & 57 deletions src/graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* @packageDocumentation
*/

import { doT } from "./cat.ts";
import { type CatT, doT } from "./cat.ts";
import {
appendToHead,
empty,
Expand All @@ -33,9 +33,9 @@ import { err, isErr, ok, type Result } from "./result.ts";
import { BinaryHeap } from "../mod.ts";
import type { Monoid } from "./type-class/monoid.ts";
import { fromProjection, type Ord } from "./type-class/ord.ts";
import type { Hkt1 } from "./hkt.ts";
import type { Apply2Only, Hkt1 } from "./hkt.ts";
import type { HasInf } from "./type-class/has-inf.ts";
import { monad as mutMonad, type Mut, runMut } from "./mut.ts";
import { doMut, type Mut, type MutHkt } from "./mut.ts";
import { mapMIgnore } from "./type-class/foldable.ts";

declare const vertexNominal: unique symbol;
Expand Down Expand Up @@ -484,60 +484,54 @@ export const dijkstra =
interface WeightedVertexHkt extends Hkt1 {
readonly type: [Vertex, this["arg1"]];
}
runMut(<S>() => {
const m = mutMonad<S>();
return doT(m)
.addM(
"heap",
BinaryHeap.empty(
fromProjection<WeightedVertexHkt>(([, weight]) =>
weight
)(order),
doMut(<S>(cat: CatT<Apply2Only<MutHkt, S>, Record<string, never>>) =>
cat.addM(
"heap",
BinaryHeap.empty(
fromProjection<WeightedVertexHkt>(([, weight]) => weight)(
order,
),
)
.runWith(({ heap }) =>
BinaryHeap.insert(
[start, monoid.identity] as WeightedVertex,
)(
heap,
)
)
.finishM(({ heap }) => {
const body: Mut<S, never[]> = doT(m)
.addM("min", BinaryHeap.popMin(heap))
.finishM(({ min }) => {
const [visiting, visitingDist] = unwrap(min);
visited.add(visiting);
dist[visiting] = visitingDist;
return mapMIgnore(foldable, m)(
(next: Vertex): Mut<S, never[]> => {
if (visited.has(next)) {
return m.pure([]);
}
const nextWeight = edgeWeight([
visiting,
next,
]);
return BinaryHeap.insert([
next,
monoid.combine(
visitingDist,
nextWeight,
),
] as WeightedVertex)(heap);
},
)(adjsFrom(visiting)(graph));
});
const loop = (
heap: BinaryHeap.BinaryHeap<S, WeightedVertex>,
): Mut<S, never[]> =>
m.flatMap((wasEmpty) =>
wasEmpty
? m.pure([])
: m.flatMap(() => loop(heap))(body)
)(BinaryHeap.isEmpty(heap));
return loop(heap);
});
});
),
).runWith(({ heap }) =>
BinaryHeap.insert(
[start, monoid.identity] as WeightedVertex,
)(heap)
).finishM(({ heap }) => {
const body = cat
.addM("min", BinaryHeap.popMin(heap))
.finishM(({ min }) => {
const [visiting, visitingDist] = unwrap(min);
visited.add(visiting);
dist[visiting] = visitingDist;
return mapMIgnore(foldable, cat.monad)(
(next: Vertex) => {
if (visited.has(next)) {
return cat.monad.pure([]);
}
const nextWeight = edgeWeight([
visiting,
next,
]);
return BinaryHeap.insert([
next,
monoid.combine(
visitingDist,
nextWeight,
),
] as WeightedVertex)(heap);
},
)(adjsFrom(visiting)(graph));
});
const loop = (
heap: BinaryHeap.BinaryHeap<S, WeightedVertex>,
): Mut<S, never[]> =>
cat.monad.flatMap((wasEmpty) =>
wasEmpty
? cat.monad.pure([])
: cat.monad.flatMap(() => loop(heap))(body)
)(BinaryHeap.isEmpty(heap));
return loop(heap);
})
);
return dist;
};
64 changes: 64 additions & 0 deletions src/multi-set.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { assertEquals } from "../deps.ts";
import {
contains,
count,
empty,
insert,
intoMut,
len,
remove,
} from "./multi-set.ts";
import { doMut, readMutRef } from "./mut.ts";

Deno.test("len", () => {
assertEquals(len(empty()), 0);

const one = doMut((cat) =>
cat.addM("set", intoMut(empty<number>()))
.runWith(({ set }) => insert(1)(set))
.finishM(({ set }) => readMutRef(set))
);
assertEquals(len(one), 1);
});

Deno.test("contains", () => {
assertEquals(contains(0)(empty()), false);
assertEquals(contains(1)(empty()), false);

const one = doMut((cat) =>
cat.addM("set", intoMut(empty<number>()))
.runWith(({ set }) => insert(1)(set))
.finishM(({ set }) => readMutRef(set))
);
assertEquals(contains(0)(one), false);
assertEquals(contains(1)(one), true);
assertEquals(contains(2)(one), false);
});

Deno.test("count", () => {
assertEquals(count(0)(empty()), 0);
assertEquals(count(1)(empty()), 0);

const one = doMut((cat) =>
cat.addM("set", intoMut(empty<number>()))
.runWith(({ set }) => insert(1)(set))
.finishM(({ set }) => readMutRef(set))
);
assertEquals(count(0)(one), 0);
assertEquals(count(1)(one), 1);
assertEquals(count(2)(one), 0);

const oneTwoTwo = doMut((cat) =>
cat.addM("set", intoMut(empty<number>()))
.runWith(({ set }) => insert(1)(set))
.runWith(({ set }) => insert(2)(set))
.runWith(({ set }) => insert(2)(set))
.addMWith("_", ({ set }) => remove(2)(set))
.runWith(({ set }) => insert(2)(set))
.finishM(({ set }) => readMutRef(set))
);
assertEquals(count(0)(oneTwoTwo), 0);
assertEquals(count(1)(oneTwoTwo), 1);
assertEquals(count(2)(oneTwoTwo), 2);
assertEquals(count(3)(oneTwoTwo), 0);
});

0 comments on commit 136ded7

Please sign in to comment.