0

Suppose we have an array of functions each one taking a number and returning a TaskEither<string, number>.

let tasks: (n: number) => TE.TaskEither<string, number>[] = [];

The goal is to provide an initial value and then execute each function in sequence with the result of the other.

A reducer is an option:

const taskEitherReducer = <E, S>(acc: TE.TaskEither<E, S>, cur: (x: S) => TE.TaskEither<E, S>) =>  
pipe(TE.map(cur)(acc), TE.flatten);

Then it is possible to define a function taking an initial value and an array of tasks:

const runTasks =   
    (initialValue: number) =>  
        A.reduce(  
            TE.of(initialValue),  
            (  
                acc: TE.TaskEither<string, number>,  
                cur: (ord: number) => TE.TaskEither<string, number>  
            ) => taskEitherReducer(acc, cur));  

Finally:

runTasks(1)(tasks);

The question:

  • All this process looks like a composition, TaskEither.chain() allows to compose functions but forces to know which functions we want to compose. In this case we don't know how many of this functions are there, only it's type.

So, is there any built-in method in fp-ts to achieve this kind of dynamic composition?

Lauren Yim
  • 12,700
  • 2
  • 32
  • 59
PSF
  • 26
  • 4

1 Answers1

0

Not sure this will answer your question but there is a reduceM combinator which generalizes the usual reduce for functions that return a monadic value. You need to provide a Monad instance for a type the function returns and a Foldable instance for the type you are folding.

import * as TE from "fp-ts/TaskEither";
import * as F from "fp-ts/Foldable";
import * as A from "fp-ts/Array";
import { pipe } from "fp-ts/lib/function";

const tasks: ((n: number) => TE.TaskEither<string, number>)[] = [];

const reduceTaskEither = F.reduceM(TE.Monad, A.Foldable);

const runTasks = (initialValue: number) =>
  pipe(
    tasks,
    reduceTaskEither(initialValue, (n, f) => f(n))
  );
sukovanej
  • 658
  • 2
  • 8
  • 18