Skip to content
This repository has been archived by the owner on May 3, 2021. It is now read-only.

Commit

Permalink
feat: set tests complete
Browse files Browse the repository at this point in the history
  • Loading branch information
baetheus committed Apr 11, 2021
1 parent d59167b commit ed65f51
Show file tree
Hide file tree
Showing 2 changed files with 174 additions and 91 deletions.
117 changes: 26 additions & 91 deletions set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,61 +27,51 @@ declare module "./hkt.ts" {

export const zero: Set<never> = new Set();

export const empty = <A = never>(): Set<A> => zero;
export const empty = <A = never>(): Set<A> => new Set();

export const make = <A>(...as: [A, ...A[]]): Set<A> => new Set(as);

/*******************************************************************************
* Utilities
******************************************************************************/

export const elem = <A>(S: TC.Setoid<A>) =>
(set: Set<A>) =>
(a: A): boolean => {
for (const b of set) {
if (S.equals(a)(b)) {
return true;
}
}
return false;
};

export const every = <A>(
export const some = <A>(
predicate: Predicate<A>,
) =>
(set: Set<A>): boolean => {
const values = set.values();
for (const a of values) {
if (!predicate(a)) {
return false;
for (const a of set) {
if (predicate(a)) {
return true;
}
}
return true;
return false;
};

export const some = <A>(
export const every = <A>(
predicate: Predicate<A>,
) =>
(set: Set<A>): boolean => {
const values = set.values();
for (const a of values) {
if (predicate(a)) {
return true;
for (const a of set) {
if (!predicate(a)) {
return false;
}
}
return false;
return true;
};

export const elem = <A>(S: TC.Setoid<A>) => (a: A) => some(S.equals(a));

export const elemOf = <A>(S: TC.Setoid<A>) =>
(set: Set<A>) => (a: A) => elem(S)(a)(set);

export const isSubset = <A>(S: TC.Setoid<A>) =>
(set: Set<A>) =>
(check: Set<A>): boolean => {
const isIn = elem(S)(set);
return every(isIn)(check);
};
(set: Set<A>) => every(elemOf(S)(set));

export const union = <A>(S: TC.Setoid<A>) =>
(as: Set<A>) =>
(bs: Set<A>): Set<A> => {
const out = new Set(as);
const isIn = elem(S)(out);
const isIn = elemOf(S)(out);
for (const b of bs) {
if (!isIn(b)) {
out.add(b);
Expand All @@ -95,7 +85,7 @@ export const intersection = <A>(S: TC.Setoid<A>) =>
(tb: Set<A>): Set<A> => {
const out = new Set<A>();
const [small, big] = ta.size > tb.size ? [tb, ta] : [ta, tb];
const isIn = elem(S)(small);
const isIn = elemOf(S)(small);
for (const b of big) {
if (isIn(b)) {
out.add(b);
Expand All @@ -107,7 +97,7 @@ export const intersection = <A>(S: TC.Setoid<A>) =>
export const compact = <A>(S: TC.Setoid<A>) =>
(ta: Set<A>): Set<A> => {
const out = new Set<A>();
const isIn = elem(S)(out);
const isIn = elemOf(S)(out);
for (const a of ta) {
if (!isIn(a)) {
out.add(a);
Expand Down Expand Up @@ -213,70 +203,15 @@ export const getSetoid = <A>(S: TC.Setoid<A>): TC.Setoid<Set<A>> => {
return fromEquals((x) => (y) => subset(x)(y) && subset(y)(x));
};

export const getUnionMonoid = <A>(S: TC.Setoid<A>): TC.Monoid<Set<A>> => {
const merge = union(S);
return ({
concat: merge,
empty,
});
};

/**
* @deprecated
*/
export const getMonad = <B>(S: TC.Setoid<B>) => {
const isElementOf = elem(S);

const Monad = {
of: (a: B) => new Set([a]),
ap: <A>(tfab: Set<Fn<[A], B>>, ta: Set<A>) =>
Monad.chain((f) => Monad.map(f, ta), tfab),
map: <A>(fab: Fn<[A], B>, ta: Set<A>): Set<B> => {
const tb = new Set<B>();
const isIn = isElementOf(tb);
for (const a of ta.values()) {
const b = fab(a);
if (!isIn(b)) {
tb.add(b);
}
}
return tb;
},
join: (tta: Set<Set<B>>): Set<B> => {
const out = new Set<B>();
const isIn = isElementOf(out);
for (const ta of tta) {
for (const a of ta) {
if (!isIn(a)) {
out.add(a);
}
}
}
return out;
},
chain: <A>(fatb: Fn<[A], Set<B>>, ta: Set<A>): Set<B> => {
const tb = new Set<B>();
const isIn = isElementOf(tb);
for (const a of ta) {
for (const b of fatb(a)) {
if (!isIn(b)) {
tb.add(b);
}
}
}
return tb;
},
};

return Monad;
};
export const getUnionMonoid = <A>(S: TC.Setoid<A>): TC.Monoid<Set<A>> => ({
concat: union(S),
empty,
});

/*******************************************************************************
* Pipeables
******************************************************************************/

export const of = <A>(a: A): Set<A> => new Set([a]);

export const { filter } = Filterable;

export const { map, reduce, traverse } = Traversable;
148 changes: 148 additions & 0 deletions testing/set.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";

import * as AS from "./assert.ts";

import * as S from "../set.ts";
import * as O from "../option.ts";
import { setoidNumber } from "../setoid.ts";
import { monoidSum } from "../monoid.ts";
import { ordNumber } from "../ord.ts";
import { semigroupSum } from "../semigroup.ts";
import { pipe } from "../fns.ts";

Deno.test("Set zero", () => {
assertEquals(S.zero, new Set());
});

Deno.test("Set empty", () => {
assertEquals(S.empty(), S.zero);
});

Deno.test("Set make", () => {
assertEquals(S.make(1), new Set([1]));
});

Deno.test("Set elem", () => {
const elem = S.elem(setoidNumber);
assertEquals(pipe(S.make(1), elem(1)), true);
assertEquals(pipe(S.make(1), elem(2)), false);
});

Deno.test("Set elemOf", () => {
const elemOf = S.elemOf(setoidNumber);
assertEquals(pipe(1, elemOf(S.make(1))), true);
assertEquals(pipe(2, elemOf(S.make(1))), false);
});

Deno.test("Set isSubset", () => {
const isSubset = S.isSubset(setoidNumber);
const ta = S.make(1);
const tb = S.make(1);
tb.add(2);
assertEquals(pipe(ta, isSubset(tb)), true);
assertEquals(pipe(tb, isSubset(ta)), false);
});

Deno.test("Set union", () => {
const union = S.union(setoidNumber);
assertEquals(pipe(S.make(1), union(S.make(2))), S.make(1, 2));
});

Deno.test("Set intersection", () => {
const intersection = S.intersection(setoidNumber);
assertEquals(pipe(S.make(1), intersection(S.make(2))), S.empty());
assertEquals(pipe(S.make(1, 2), intersection(S.make(2, 3))), S.make(2));
});

Deno.test("Set compact", () => {
const compact = S.compact(setoidNumber);
assertEquals(compact(S.make(1, 2, 3)), S.make(1, 2, 3));
});

Deno.test("Set join", () => {
assertEquals(S.join(S.make(S.make(1, 2), S.make(2, 3))), S.make(1, 2, 3));
});

Deno.test("Set Functor", () => {
AS.assertFunctor(S.Functor, {
ta: S.make(1, 2, 3),
fai: AS.add,
fij: AS.multiply,
});
});

Deno.test("Set Apply", () => {
AS.assertApply(S.Apply, {
ta: S.make(1, 2, 3),
fai: AS.add,
fij: AS.multiply,
tfai: S.make(AS.add, AS.multiply),
tfij: S.make(AS.multiply, AS.add),
});
});

Deno.test("Set Filterable", () => {
AS.assertFilterable(S.Filterable, {
a: S.make(1, 2, 3),
b: S.make(2, 3, 4),
f: (n: number) => n < 2,
g: (n: number) => n > 4,
});
});

Deno.test("Set Foldable", () => {
AS.assertFoldable(S.Foldable, {
a: 0,
tb: S.make(1, 2, 3),
faia: (n: number, i: number) => n + i,
});
});

Deno.test("Set getShow", () => {
const { show } = S.getShow({ show: (n: number) => n.toString() });
assertEquals(show(S.empty()), "Set([])");
assertEquals(show(S.make(1, 2, 3)), "Set([1, 2, 3])");
});

Deno.test("Set getSetoid", () => {
const Setoid = S.getSetoid(setoidNumber);
AS.assertSetoid(Setoid, {
a: S.make(1),
b: S.make(1),
c: S.make(1),
z: S.make(1, 2, 3),
});
});

Deno.test("Set getUnionMonoid", () => {
const Monoid = S.getUnionMonoid(setoidNumber);
AS.assertMonoid(Monoid, {
a: S.make(1, 2),
b: S.make(2, 3),
c: S.make(3, 4),
});
});

Deno.test("Set filter", () => {
const filter = S.filter((n: number) => n > 0);
assertEquals(filter(S.make(1, 2, 3)), S.make(1, 2, 3));
assertEquals(filter(S.make(-1, 0, 1)), S.make(1));
});

Deno.test("Set map", () => {
assertEquals(pipe(S.make(1, 2, 3), S.map(AS.add)), S.make(2, 3, 4));
});

Deno.test("Set reduce", () => {
const reduce = S.reduce((n: number, o: number) => n + o, 0);
assertEquals(reduce(S.zero), 0);
assertEquals(reduce(S.make(1, 2, 3)), 6);
});

Deno.test("Set traverse", () => {
const t1 = S.traverse(O.Applicative);
const t2 = t1((n: number) => n === 0 ? O.none : O.some(n));
assertEquals(t2(S.empty()), O.some(S.empty()));
assertEquals(t2(S.make(1, 2, 3)), O.some(S.make(1, 2, 3)));
assertEquals(t2(S.make(0, 1, 2)), O.none);
});

0 comments on commit ed65f51

Please sign in to comment.