4.5 Extending Promise to Functor

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

by dimitrs_papadimitriou

HTML

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

JavaScript

class Either {
    map(f) {
      throw new Error('You have to implement the method map!');
    }
    matchWith(pattern) {
      throw new Error('You have to implement the method matchWith!');
    }
    bind(f) {
      return this.matchWith({
        left: (e) => new Left(e),
        right: (v) => f(v)
      })
    }
  }

  class Right extends Either {
    constructor(value) {
      super();
      this.value = value;
    }

    map(f) {
      return new Right(f(this.value))
    }

    matchWith(pattern) {
      return pattern.right(this.value)
    }

  }

  class Left extends Either {
    constructor(value) {
      super();
      this.value = value;
    }

    map(f) {
      return new Left(this.value);
    }
    matchWith(pattern) {
      return pattern.left(this.value)
    }
  }

  (function () {

    const compose = (...fns) => x => fns.reduceRight((y, f) => f(y), x);

    const id = x => x;

    const EitherAsync = (actions, resolveMappings, rejectMappings) => ({

      map: (f) => EitherAsync(actions, compose(f, resolveMappings), rejectMappings),

      bind: f => EitherAsync((resolve, reject) => actions(x => f(resolveMappings(x)).matchWith({
        right: resolve,
        left: reject
      }), reject), id, id),

      matchWith: alg => actions(compose(alg.right, resolveMappings), compose(alg.left, rejectMappings)),

      toPromise: () => new Promise((resolve, reject) => actions(compose(resolve, resolveMappings), compose(reject, rejectMappings))),
      toEither: () => EitherAsync(actions, resolveMappings, rejectMappings),

    });

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

  }())
 
 
  Promise.prototype.matchWith = function (pattern) {
    return this.then(pattern.right).catch(pattern.left)
  }
  Promise.prototype.bind = function (f) {
    return this.then(f)
  }
  Promise.prototype.map = function (f) {
    return this.then(f)
  }
  var...