Functor

https://github.com/eu81273/jsfiddle-console

by dimitrs_papadimitriou

HTML

<script src="https://rawgit.com/eu81273/jsfiddle-console/master/console.js"></script>

JavaScript

const Ok = v => ({
      map: f => Ok(f(v)),
      chain: f => f(v),
      cata: alg => alg.Ok(v)
   });

   const Error = v => ({
      map: () => Error(v),
      chain: () => Error(v),
      cata: alg => alg.Error(v)
   });

   var Reader = (expr) => ({
      ask: () => expr,
      map: f => Reader(env => f(expr(env))),
      run: env => expr(env),
      ap: reader => Reader(env => Reader(expr).run(env)(reader.run(env))),
      chain: f => Reader(env => f(expr(env)).run(env)),
   });

   var safe = f => {
      try {
         return Ok(f())
      } catch (e) {
         return Error(e)
      }
   }

   (function () {

      const compose = (...fns) => fns.reduceRight((g, f) => x => g(f(x)), x => x);
      const composeM = (...fns) => fns.reduceRight((g, f) => x => g(x).chain(f), Ok);

      const EitherAsync = (actions, res, rej) => ({
         map: (f) => EitherAsync(actions, composeM(x => Ok(x).map(f), res), rej),
         mapError: (f) => EitherAsync(actions, res, compose(f, rej)),
         chain: f => EitherAsync(actions, composeM(f, res), rej),
         app: fv => EitherAsync(actions, composeM(f => fv.map(f), res), rej),
         cata: alg => actions(x => res(x).cata(alg), composeM(alg.Error, rej)),
         toEither: () => EitherAsync(actions, res, rej),
         chainReader: reader => EitherAsync(actions, x => safe(() => (reader.run(x))).chain(res), rej),
      });

      Promise.prototype.toEither = function () {
         return EitherAsync((resolve, reject) => this.then(resolve).catch(reject), Ok, Ok);
      }

      var toEither = (promise) => {
         return EitherAsync((resolve, reject) => promise.then(resolve).catch(reject), Ok, Ok);
      }
 
   }())


   Array.prototype.traverse = function (TyperRep, f) {
      if (this.length === 0) {
         return TyperRep([]);
      } else {
         var head = this.shift();
         return TyperRep(x => y => x.concat(y))
            .ap(f(head).map(x => [x]))
            .ap(this.traverse(TyperRep, f));
  ...