diff --git a/task.ts b/task.ts index 8a2e4a1..4b71f97 100644 --- a/task.ts +++ b/task.ts @@ -2,7 +2,7 @@ import type * as HKT from "./hkt.ts"; import type * as TC from "./type_classes.ts"; import { Lazy } from "./types.ts"; -import { apply, flow, wait } from "./fns.ts"; +import { apply, flow, wait, identity } from "./fns.ts"; import { createDo } from "./derivations.ts"; /******************************************************************************* @@ -30,6 +30,8 @@ declare module "./hkt.ts" { * Combinators ******************************************************************************/ +export const make = (a: A): Task => () => Promise.resolve(a); + export const delay = (ms: number) => (ma: Task): Task => () => wait(ms).then(ma); @@ -75,7 +77,7 @@ export const Monad: TC.Monad = { of: Applicative.of, ap: Apply.ap, map: Functor.map, - join: (tta) => () => tta().then(apply()), + join: Chain.chain(identity), chain: Chain.chain, }; @@ -92,7 +94,7 @@ export const MonadSeq: TC.Monad = { of: Applicative.of, ap: ApplySeq.ap, map: Functor.map, - join: (tta) => () => tta().then(apply()), + join: Chain.chain(identity), chain: Chain.chain, }; @@ -102,6 +104,8 @@ export const MonadSeq: TC.Monad = { export const { of, ap, map, join, chain } = Monad; +export const { ap: apSeq } = ApplySeq; + /******************************************************************************* * Do Notation ******************************************************************************/ diff --git a/testing/task.test.ts b/testing/task.test.ts new file mode 100644 index 0000000..9c0d604 --- /dev/null +++ b/testing/task.test.ts @@ -0,0 +1,69 @@ +import { assertEquals } from "https://deno.land/std/testing/asserts.ts"; + +import * as T from "../task.ts"; +import { _, pipe } from "../fns.ts"; + +import * as AS from "./assert.ts"; + +const assertEqualsT = async (a: T.Task, b: T.Task) => + assertEquals(await a(), await b()); + +Deno.test("Task make", async () => { + await assertEqualsT(T.make(0), T.make(0)); +}); + +Deno.test("Task delay", async () => { + await assertEqualsT(pipe(T.make(0), T.delay(200)), T.make(0)); +}); + +Deno.test("Task fromThunk", async () => { + await assertEqualsT(T.fromThunk(() => 0), T.make(0)); +}); + +Deno.test("Task tryCatch", async () => { + await assertEqualsT(T.tryCatch(_, () => 0), T.make(0)); + await assertEqualsT(T.tryCatch(() => 1, () => 0), T.make(1)); +}); + +Deno.test("Task of", async () => { + await assertEqualsT(T.of(1), T.make(1)); +}); + +Deno.test("Task ap", async () => { + await assertEqualsT(pipe(T.of(1), T.ap(T.of(AS.add))), T.of(2)); +}); + +Deno.test("Task map", async () => { + await assertEqualsT(pipe(T.of(1), T.map(AS.add)), T.of(2)); +}); + +Deno.test("Task join", async () => { + await assertEqualsT(T.join(T.of(T.of(1))), T.of(1)); +}); + +Deno.test("Task chain", async () => { + await assertEqualsT(pipe(T.of(1), T.chain((n) => T.of(n + 1))), T.of(2)); +}); + +Deno.test("Task apSeq", async () => { + await assertEqualsT(pipe(T.of(1), T.apSeq(T.of(AS.add))), T.of(2)); +}); + +Deno.test("Task Do, bind, bindTo", () => { + assertEqualsT( + pipe( + T.Do(), + T.bind("one", () => T.make(1)), + T.bind("two", ({ one }) => T.make(one + one)), + T.map(({ one, two }) => one + two), + ), + T.make(3), + ); + assertEqualsT( + pipe( + T.make(1), + T.bindTo("one"), + ), + T.make({ one: 1 }), + ); +});