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

Commit

Permalink
feat: io tests complete
Browse files Browse the repository at this point in the history
  • Loading branch information
baetheus committed Apr 10, 2021
1 parent 1134c3a commit 36b5248
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 16 deletions.
28 changes: 21 additions & 7 deletions derivations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,34 @@ export const createDo = <URI extends URIS>(
name: N,
): (<A, B, C, D>(
ta: Kind<URI, [A, B, C, D]>,
// deno-lint-ignore no-explicit-any
) => Kind<URI, [{ [K in N]: A }, B, C, D]>) =>
// deno-lint-ignore no-explicit-any
M.map((a: any): any => ({ [name]: a })),
bind: <N extends string, A, I, B, C, D>(
name: Exclude<N, keyof A>,
fati: (a: A) => Kind<URI, [I, B, C, D]>,
): ((
ma: Kind<URI, [A, B, C, D]>,
) => Kind<
URI,
[{ readonly [K in keyof A | N]: K extends keyof A ? A[K] : I }, B, C, D]
> // deno-lint-ignore no-explicit-any
): (
(
ma: Kind<URI, [A, B, C, D]>,
) => Kind<
URI,
[{ readonly [K in keyof A | N]: K extends keyof A ? A[K] : I }, B, C, D]
>
) =>
// deno-lint-ignore no-explicit-any
M.chain((a: any): any =>
// deno-lint-ignore no-explicit-any
pipe(a, fati, M.map((b: any): any => ({ ...a, [name]: b })))
),
});

/*******************************************************************************
* Derive getSemigroup from Apply
******************************************************************************/

export const createApplySemigroup = <URI extends URIS>(A: TC.Apply<URI>) =>
<A, B = never, C = never, D = never>(
S: TC.Semigroup<A>,
): TC.Semigroup<Kind<URI, [A, B, C, D]>> => ({
concat: (a) => A.ap(pipe(a, A.map(S.concat))),
});
13 changes: 4 additions & 9 deletions io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type * as TC from "./type_classes.ts";

import { createSequenceStruct, createSequenceTuple } from "./sequence.ts";
import { apply, constant, flow, pipe } from "./fns.ts";
import { createDo } from "./derivations.ts";
import { createApplySemigroup, createDo } from "./derivations.ts";

/*******************************************************************************
* Types
Expand Down Expand Up @@ -59,11 +59,6 @@ export const Monad: TC.Monad<URI> = {
chain: Chain.chain,
};

export const Alt: TC.Alt<URI> = {
alt: constant,
map: Monad.map,
};

export const Extends: TC.Extend<URI> = {
map: Monad.map,
extend: (ftab) => (ta) => () => ftab(ta),
Expand All @@ -83,9 +78,7 @@ export const Traversable: TC.Traversable<URI> = {
* Module Getters
******************************************************************************/

export const getSemigroup = <A>(S: TC.Semigroup<A>): TC.Semigroup<IO<A>> => ({
concat: (x) => (y) => () => S.concat(x())(y()),
});
export const getSemigroup = createApplySemigroup(Apply);

export const getMonoid = <A>(M: TC.Monoid<A>): TC.Monoid<IO<A>> => ({
...getSemigroup(M),
Expand All @@ -100,6 +93,8 @@ export const { of, ap, map, join, chain } = Monad;

export const { reduce, traverse } = Traversable;

export const { extend } = Extends;

/*******************************************************************************
* Sequenec
******************************************************************************/
Expand Down
99 changes: 99 additions & 0 deletions testing/io.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";

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

import * as I from "../io.ts";
import * as O from "../option.ts";
import { semigroupSum } from "../semigroup.ts";
import { monoidSum } from "../monoid.ts";
import { pipe } from "../fns.ts";

// deno-lint-ignore no-explicit-any
const assertEqualsIO = (a: I.IO<any>, b: I.IO<any>) => assertEquals(a(), b());

Deno.test("IO getSemigroup", () => {
const Semigroup = I.getSemigroup(semigroupSum);
const concat = Semigroup.concat(I.of(1));

assertEqualsIO(concat(I.of(1)), I.of(2));
});

Deno.test("IO getMonoid", () => {
const Monoid = I.getMonoid(monoidSum);
const empty = Monoid.empty();

assertEqualsIO(empty, I.of(0));
});

Deno.test("IO of", () => {
assertEqualsIO(I.of(1), I.of(1));
});

Deno.test("IO ap", () => {
const ap = I.ap(I.of(AS.add));
assertEqualsIO(ap(I.of(1)), I.of(2));
});

Deno.test("IO map", () => {
const map = I.map(AS.add);
assertEqualsIO(map(I.of(1)), I.of(2));
});

Deno.test("IO join", () => {
assertEqualsIO(I.join(I.of(I.of(1))), I.of(1));
});

Deno.test("IO chain", () => {
const chain = I.chain((n: number) => I.of(n + 1));
assertEqualsIO(chain(I.of(1)), I.of(2));
});

Deno.test("IO reduce", () => {
const reduce = I.reduce((acc: number, cur: number) => acc + cur, 0);
assertEquals(reduce(I.of(1)), 1);
});

Deno.test("IO traverse", () => {
const fold = O.fold((n: I.IO<number>) => n(), () => -1);
const t0 = I.traverse(O.Applicative);
const t1 = t0((n: number) => n === 0 ? O.none : O.some(n));
const t2 = fold(t1(I.of(0)));
const t3 = fold(t1(I.of(1)));

assertEquals(t2, -1);
assertEquals(t3, 1);
});

Deno.test("IO extend", () => {
const extend = I.extend((ta: I.IO<number>) => ta() + 1);
assertEqualsIO(extend(I.of(1)), I.of(2));
});

Deno.test("IO sequenceTuple", () => {
const r1 = I.sequenceTuple(I.of(1), I.of("Hello World"));
assertEqualsIO(r1, I.of([1, "Hello World"]));
});

Deno.test("IO sequenceStruct", () => {
const r1 = I.sequenceStruct({ a: I.of(1), b: I.of("Hello World") });
assertEqualsIO(r1, I.of({ a: 1, b: "Hello World" }));
});

Deno.test("IO Do, bind, bindTo", () => {
assertEqualsIO(
pipe(
I.Do(),
I.bind("one", () => I.of(1)),
I.bind("two", ({ one }) => I.of(one + one)),
I.map(({ one, two }) => one + two),
),
I.of(3),
);
assertEqualsIO(
pipe(
I.of(1),
I.bindTo("one"),
),
I.of({ one: 1 }),
);
});

0 comments on commit 36b5248

Please sign in to comment.