Skip to content

Commit

Permalink
Add a right-biased disjunction type
Browse files Browse the repository at this point in the history
  • Loading branch information
earldouglas committed Jul 26, 2018
1 parent e2ac9d6 commit 4fb0a5e
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 26 deletions.
39 changes: 39 additions & 0 deletions docs/1.5.md
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,45 @@ parse('21').flatMap(function (x) {
}).toString(); // some(42)
```

### Either

An `Either` instance exposes the following fields:

* `left` - whether this is a `Left` instance
* `right` - whether this is a `Right` instance
* `map(f)` - returns a new `Either` by applying `f` over this `Either`'s
value, and wrapping the result in an `Either`
* `flatMap(f)` - returns a new `Either` by applying `f` over this
`Either`'s value, and returning the result
* `toString()`

#### `left(value)`

`left` constructs a representation of an error-like value, such as an
error message, that can't be used for further computation.

#### `right(value)`

`right` constructs a representation of a value that can be used for
further computation.

*Example:*

```javascript
function timesTwo(x) {
return x * 2;
}

left('file not found').map(timesTwo).toString(); // left(file not found)
right(21).map(timesTwo).toString(); // right(42)

right('21').flatMap(function (x) {
return right('2').map(function (y) {
return x * y;
});
}).toString(); // right(42)
```

### Promise

#### `promise.collect(promises, callback)`
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"istanbul": "0.3.5",
"mocha": "2.2.5",
"mocha-lcov-reporter": "0.0.1",
"typescript": "1.5.0-beta"
"typescript": "2.9"
},
"keywords": [
"functional",
Expand Down
36 changes: 36 additions & 0 deletions src/teep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,40 @@ module edc {
}
}

export interface Either<A,B> extends Monad<A> {
left : boolean;
right : boolean;
map : <C>(f: (B) => C) => Either<A,C>;
flatMap : <C>(f: (B) => Either<A,C>) => Either<A,C>;
}

class Right<B> implements Either<never,B> {
value: B;
constructor(value: B) {
this.value = value;
}
left = false;
right = true;
map = (f) => { return new Right(f(this.value)); };
flatMap = (f) => { return f(this.value); };
toString = () => { return 'right(' + this.value.toString() + ')'; };
}

class Left<A> implements Either<A,never> {
value: A;
constructor(value: A) {
this.value = value;
}
left = true;
right = false;
map = () => { return this; };
flatMap = () => { return this; };
toString = () => { return 'left(' + this.value.toString() + ')'; };
}

var right = <A,B>(value: B): Either<A,B> => { return new Right(value); };
var left = <A,B>(value: A): Either<A,B> => { return new Left(value); };

export interface Validation<A> extends Monad<A> {
valid : boolean;
map : <B>(f: (A) => B) => Validation<B>;
Expand Down Expand Up @@ -434,6 +468,8 @@ module edc {
future: future,
readerT: readerT,
state: state,
left: left,
right: right,
};

var setExports = function () {
Expand Down
78 changes: 53 additions & 25 deletions teep.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@ var edc;
return ks;
}
};
var DumbCache = (function () {
var DumbCache = /** @class */ (function () {
function DumbCache() {
var _this = this;
this.cache = {};
this.get = function (k) { return _this.cache[k]; };
this.put = function (k, v) { _this.cache[k] = v; };
}
return DumbCache;
})();
}());
var fn = {
compose: function (f, g) {
return function (x) {
Expand Down Expand Up @@ -146,7 +146,7 @@ var edc;
return throttled;
}
};
var Some = (function () {
var Some = /** @class */ (function () {
function Some(value) {
var _this = this;
this.empty = false;
Expand All @@ -157,8 +157,8 @@ var edc;
this.value = value;
}
return Some;
})();
var None = (function () {
}());
var None = /** @class */ (function () {
function None() {
var _this = this;
this.empty = true;
Expand All @@ -168,7 +168,7 @@ var edc;
this.toString = function () { return 'none()'; };
}
return None;
})();
}());
var _none = new None();
var option = function (value) {
if (value !== null && typeof value !== 'undefined') {
Expand All @@ -178,7 +178,33 @@ var edc;
return _none;
}
};
var Valid = (function () {
var Right = /** @class */ (function () {
function Right(value) {
var _this = this;
this.left = false;
this.right = true;
this.map = function (f) { return new Right(f(_this.value)); };
this.flatMap = function (f) { return f(_this.value); };
this.toString = function () { return 'right(' + _this.value.toString() + ')'; };
this.value = value;
}
return Right;
}());
var Left = /** @class */ (function () {
function Left(value) {
var _this = this;
this.left = true;
this.right = false;
this.map = function () { return _this; };
this.flatMap = function () { return _this; };
this.toString = function () { return 'left(' + _this.value.toString() + ')'; };
this.value = value;
}
return Left;
}());
var right = function (value) { return new Right(value); };
var left = function (value) { return new Left(value); };
var Valid = /** @class */ (function () {
function Valid(value) {
var _this = this;
this.valid = true;
Expand All @@ -189,8 +215,8 @@ var edc;
this.value = value;
}
return Valid;
})();
var Invalid = (function () {
}());
var Invalid = /** @class */ (function () {
function Invalid(errors) {
var _this = this;
this.valid = false;
Expand All @@ -201,12 +227,12 @@ var edc;
this.errors = errors;
}
return Invalid;
})();
}());
var validation = {
valid: function (value) { return new Valid(value); },
invalid: function (errors) { return new Invalid(errors); }
};
var Nil = (function () {
var Nil = /** @class */ (function () {
function Nil() {
var _this = this;
this.length = 0;
Expand All @@ -216,8 +242,8 @@ var edc;
this.toString = function () { return 'nil'; };
}
return Nil;
})();
var Cons = (function () {
}());
var Cons = /** @class */ (function () {
function Cons(head, tail) {
var _this = this;
this.map = function (f) { return new Cons(f(_this.head), _this.tail.map(f)); };
Expand All @@ -229,7 +255,7 @@ var edc;
this.length = 1 + this.tail.length;
}
return Cons;
})();
}());
var _nil = new Nil();
var list = function (head, tail) {
if (tail === undefined || tail === null) {
Expand All @@ -254,7 +280,7 @@ var edc;
return p.then(function (r) { return f(r); });
}
};
var Reader = (function () {
var Reader = /** @class */ (function () {
function Reader(f) {
this.f = f;
}
Expand All @@ -277,12 +303,12 @@ var edc;
};
;
return Reader;
})();
}());
var reader = function (f) { return new Reader(f); };
var read = new Reader(function (x) {
return x;
});
var Future = (function () {
var Future = /** @class */ (function () {
function Future(f) {
this.f = f;
}
Expand Down Expand Up @@ -330,9 +356,9 @@ var edc;
};
;
return Future;
})();
}());
var future = function (f) { return new Future(f); };
var ReaderT = (function () {
var ReaderT = /** @class */ (function () {
function ReaderT(f) {
this.f = f;
}
Expand All @@ -355,17 +381,17 @@ var edc;
};
;
return ReaderT;
})();
}());
var readerT = function (f) { return new ReaderT(f); };
var StateTuple = (function () {
var StateTuple = /** @class */ (function () {
function StateTuple(s, a) {
this.state = s;
this.value = a;
}
return StateTuple;
})();
}());
var state = function (f) { return new State(f); };
var State = (function () {
var State = /** @class */ (function () {
function State(f) {
this.f = f;
}
Expand All @@ -391,7 +417,7 @@ var edc;
};
;
return State;
})();
}());
edc.teep = {
array: array,
fn: fn,
Expand All @@ -403,7 +429,9 @@ var edc;
read: read,
future: future,
readerT: readerT,
state: state
state: state,
left: left,
right: right
};
var setExports = function () {
array.map(object.keys(edc.teep), function (k) {
Expand Down
29 changes: 29 additions & 0 deletions test/examples.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,35 @@ describe('examples', function () {
});
});

describe('either', function () {
var either42 = function (x) {
if (x === 42) {
return teep.right(x);
} else {
return teep.left('not forty-two');
}
};

it('constructor', function () {
assert( teep.left("error'd").left);
assert(!teep.left("error'd").right);
assert( teep.right(42).right);
assert(!teep.right(42).left);
});

it('map', function () {
assert.equal("left(error'd)", teep.left("error'd").map(times(2)).toString());
assert.equal('right(42)', teep.right(21).map(times(2)).toString());
});

it('flatMap', function () {
assert.equal("left(error'd)", teep.left("error'd").flatMap(either42).toString());
assert.equal('left(not forty-two)', teep.right(41).flatMap(either42).toString());
assert.equal('right(42)', teep.right(42).flatMap(either42).toString());
});

});

describe('promise', function () {
it('collect', function (done) {
var p = teep.promise.collect([
Expand Down

0 comments on commit 4fb0a5e

Please sign in to comment.