import { Task } from "https://deno.land/x/functional@v1.3.4/mod.js";
Task
The Task
type is similar in concept to IO
; it helps keep your function pure when you are working with IO
.
The biggest difference with IO
is that this type considers Promise as first-class citizen. Also, it always resolves
to an instance of Either
; Either.Right
for a success, Either.Left
for a failure.
The IO
type implements the following algebras:
- [x] Monad
Example
import Task from "https://deno.land/x/functional@v1.3.2/library/Task.js";
const containerA = Task(_ => readFile(`${Deno.cwd()}/dump/hoge`))
.map(text => text.split("\n"));
// File isn't being read yet. Still pure.
assert(Task.is(containerA));
const containerB = await container.run();
// Now, the file is being read.
assert(Either.Right.is(containerB));
// The call was successful!
const lines = containerB.extract();
The Task
factory comes with a special utility method called wrap
. The result of any function called with wrap
will be memoized allowing for safe "logic-forks".
Take the following example; containerD
contains the raw text, containerE
contains the text into lines and
containerF
contains the lines in inverted order. Because run
was called thrice, the file was read thrice. 😐
let count = 0;
const containerA = Task(_ => ++count && readFile(`${Deno.cwd()}/dump/hoge`));
const containerB = containerA.map(text => text.split("\n"));
const containerC = containerB.map(lines => text.reverse());
assert(Task.is(containerA));
assert(Task.is(containerB));
assert(Task.is(containerC));
const containerD = await containerA.run();
const containerE = await containerB.run();
const containerF = await containerC.run();
assert(count === 3);
Definitely not what we want... Simply wrap the function and bim bam boom - memoization magic! (The file will only be read once) 🤩
Please check-out Functional IO for more practical examples.