Capture Side Effects in a Task

Share this video with your friends

Send Tweet

We examine the data structure Task, see some constructors, familiar methods, and finally how it captures side effects through laziness.

Cristian Gabbanini
Cristian Gabbanini
~ 6 years ago

Hi Brian (or Prof. Frisby depending on who answers), I'd like to ask you a question. I'm using a Task to capture a js library that I'm using to drag and drop elements, and I would like to chain my event handlers as per the following snippet (which of course doesn't work):

const dragNDrop = lib =>
    Task.of( lib )
    .map( initLib=> initLib() )
    .map( l => l.on("drag", dragEventHandler) )
    .map( l => l.on("drop", dropEventHandler) )
    .map( l => l.on("cancel", cancelDragEventHandler) )

The map method, as per its definition, works only the first and the second time it is called and, from the third time on, it stops working as it receives undefined as its argument (calling lib.on("event", handler) does return undefined). This behavior makes me question my choice: is Task the right data type to use in these situations? Maybe is mapping the wrong choice?

Before I go, I'd like to thank you for this whole course: it has been really usefull (even If I think I'll need to watch it a few more times to sink in more concepts). Thank you!

Cristian Gabbanini
Cristian Gabbanini
~ 6 years ago
Jan Hesters
Jan Hesters
~ 5 years ago

The API for folktale has changed drastically. Here is the code for the updated API:

const { of, rejected, task } = require("folktale/concurrency/task");

of(1)
  .run()
  .listen({
    onRejected: e => console.log("err", e),
    onResolved: x => console.log("success", x)
  });

rejected(1)
  .map(x => x + 1)
  .run()
  .listen({
    onRejected: e => console.log("err", e),
    onResolved: x => console.log("success", x)
  });

of(1)
  .map(x => x + 1)
  .chain(x => of(x + 1))
  .run()
  .listen({
    onRejected: e => console.log("err", e),
    onResolved: x => console.log("success", x)
  });

const launchMissiles = () =>
  task(resolver => {
    console.log("launch missiles!");
    resolver.resolve("missile");
    // resolver.cleanup(() => {
    //   //
    // });
  });

const app = launchMissiles().map(x => x + "!");

app
  .map(x => x + "!")
  .run()
  .listen({
    onRejected: e => console.log("err", e),
    onResolved: x => console.log("success", x)
  });
Rajesh
Rajesh
~ 5 years ago

Hi Brain,

I was converting your todo app with fp-ts library(https://gcanti.github.io/fp-ts/). Below are some code whcih i want to clear.

const saveInStorage = (todos: Todo[]) => { return task .of(todos) .map(todos => JSON.stringify(todos)) .chain(todos => { return new Task(() => Promise.resolve(sessionStorage.setItem("Todos", todos)) ); }) .map(() => todos); };

export const saveTodo = (todoName: string, todos: Todo[]) => { return fromNullable("")(todoName) .map(name => new Todo(uuid4(), name)) .map(todo => todos.concat(todo)) .map(saveInStorage); }; when calling saveTodo(...) without .map(saveInStorage); then saveTodo return type is Either<string, Todo[]> but calling with .map(saveInStorage); then saveTodo return type is Either<string, Task<Todo[]>>

Please help me how my funtion saveTodo always return Either<string, Todo[]>.