typecat
Version:
A tiny functional programming library for TypeScript that provides Option (Some/None) and Either(Left/Right) with functor map, applicative map and monad flatmap
267 lines • 10.3 kB
JavaScript
;
var __values = (this && this.__values) || function (o) {
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
if (m) return m.call(o);
return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
};
Object.defineProperty(exports, "__esModule", { value: true });
var index_1 = require("./index");
describe('id', function () {
test('for any value, id returns exactly the same value', function () {
var Person = (function () {
function Person(name, age) {
this._name = name;
this._age = age;
}
Object.defineProperty(Person.prototype, "name", {
get: function () {
return this._name;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Person.prototype, "age", {
get: function () {
return this._age;
},
enumerable: true,
configurable: true
});
return Person;
}());
var jack = new Person('Jace London', 35);
var plus = function (a) { return a + 1; };
expect(index_1.id(0)).toBe(0);
expect(index_1.id(undefined)).toBeUndefined();
expect(index_1.id(null)).toBeNull();
expect(index_1.id(plus)).toBe(plus);
expect(index_1.id(jack)).toBe(jack);
});
});
describe('Option functor', function () {
test('Law: Some.fmap(id) === id(Some)', function () {
var a = new index_1.Some(33);
expect(a.fmap(index_1.id)).toEqual(index_1.id(a));
});
test('Law None.fmap(id) = id(None)', function () {
var a = new index_1.None();
expect(a.fmap(index_1.id)).toEqual(index_1.id(a));
});
test(' Some(a).fmap(f) === Some(f(a))', function () {
var i = 5;
var a = new index_1.Some(i);
var f = function (a) { return a + 2; };
expect(a.fmap(f)).toEqual(new index_1.Some(f(i)));
});
test(' None.fmap(f) = None', function () {
var a = new index_1.None();
var f = function (a) { return a + 2; };
expect(a.fmap(f)).toEqual(new index_1.None());
});
});
describe('Option applicative', function () {
test('Law Some(id).applyMap( Some(a)) = Some(id(a))', function () {
var i = 33;
var a = new index_1.Some(i);
expect(new index_1.Some(index_1.id).applyMap(a)).toEqual(new index_1.Some(index_1.id(i)));
});
test('Some(f).applyMap( Some(a)) = (Some(f(a))', function () {
var i = 33;
var a = new index_1.Some(i);
var f = function (a) { return a + 2; };
expect(new index_1.Some(f).applyMap(a)).toEqual(new index_1.Some(f(i)));
});
test('Some(f(a,b)).applyMap( Some(a)).applyMap(Some(b)) = (Some(f(a,b))', function () {
var i = 3;
var j = 4;
var a = new index_1.Some(i);
var b = new index_1.Some(j);
var f = function (a) { return function (b) { return a * 2 + b; }; };
expect(new index_1.Some(f).applyMap(a).applyMap(b)).toEqual(new index_1.Some(f(i)(j)));
});
});
describe('Option iterator', function () {
test('for iterator of Some(a) equals a ', function () {
var e_1, _a;
var i = 33;
var a = new index_1.Some(i);
try {
for (var a_1 = __values(a), a_1_1 = a_1.next(); !a_1_1.done; a_1_1 = a_1.next()) {
var b = a_1_1.value;
expect(b).toEqual(i);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (a_1_1 && !a_1_1.done && (_a = a_1.return)) _a.call(a_1);
}
finally { if (e_1) throw e_1.error; }
}
});
test('for iterator of None, iterator return done immediately ', function () {
var e_2, _a;
var a = new index_1.None();
var w = 0;
try {
for (var a_2 = __values(a), a_2_1 = a_2.next(); !a_2_1.done; a_2_1 = a_2.next()) {
var b = a_2_1.value;
w = 1;
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (a_2_1 && !a_2_1.done && (_a = a_2.return)) _a.call(a_2);
}
finally { if (e_2) throw e_2.error; }
}
expect(w).not.toBe(1);
});
});
describe('Option monad', function () {
test('Some(a).flatMap(f: (a)=>Some(b)) === Some(b) ', function () {
var i = 33;
var a = new index_1.Some(i);
var f = function (a) { return new index_1.Some(typeof a); };
expect(a.flatMap(f)).toEqual(f(i));
});
test('Some(a).flatMap(f: (a)=> None) === None ', function () {
var a = new index_1.None();
var f = function (a) { return new index_1.Some(typeof a); };
expect(a.flatMap(f)).toEqual(new index_1.None());
});
test('None.flatMap(f: (a)=>b) === None ', function () {
var a = new index_1.None();
var f = function (a) { return new index_1.Some(typeof a); };
expect(a.flatMap(f)).toEqual(new index_1.None());
});
});
describe('Either functor', function () {
test('Law: Right.fmap(id) === id(Right)', function () {
var a = new index_1.Right(33);
expect(a.fmap(index_1.id)).toEqual(index_1.id(a));
});
test('Law Left.fmap(id) = id(Left)', function () {
var a = new index_1.Left(44);
expect(a.fmap(index_1.id)).toEqual(index_1.id(a));
});
test(' Right(a).fmap(f) === Right(f(a))', function () {
var i = 5;
var a = new index_1.Right(i);
var f = function (a) { return a + 2; };
expect(a.fmap(f)).toEqual(new index_1.Right(f(i)));
});
test(' Left(a).fmap(f) === Left(a)', function () {
var i = 5;
var a = new index_1.Left(i);
var f = function (a) { return a + 2; };
expect(a.fmap(f)).toEqual(new index_1.Left(i));
});
});
describe('Either applicative', function () {
test('Law: Right.applyMap(Right(id)) === id(Right)', function () {
var a = new index_1.Right(33);
var rid = new index_1.Right(index_1.id);
expect(rid.applyMap(a)).toEqual(index_1.id(a));
});
test('Law: Left.applyMap(Right(id)) === id(Left)', function () {
var a = new index_1.Right(33);
var lid = new index_1.Left(index_1.id);
expect(lid.applyMap(a)).toEqual(index_1.id(new index_1.Left(index_1.id)));
});
test('Law: Right.applyMap(Left) === Left', function () {
var a = new index_1.Right(function (a, b) { return a + b; });
var b = new index_1.Left(45);
expect(a.applyMap(b)).toEqual(b);
});
test('Law: Lefta.applyMap(Leftb) === Leftb', function () {
var a = new index_1.Left(function (a, b) { return a + b; });
var b = new index_1.Left(45);
expect(a.applyMap(b)).toEqual(b);
});
});
describe('Either monad', function () {
test('Law: Right.flatMap( f:(a) => Right(b) === Right(b)', function () {
var i = 33;
var a = new index_1.Right(33);
var f = function (a) { return new index_1.Right(a.toString()); };
expect(a.flatMap(f)).toEqual(new index_1.Right(i.toString()));
});
test('Law: Left.flatMap( f:(a) => Right(b) === Left', function () {
var i = 33;
var a = new index_1.Left(i);
var f = function (a) { return new index_1.Right(a.toString()); };
expect(a.flatMap(f)).toEqual(new index_1.Left(i));
});
test('Law: Right.flatMap( f:(a) => Left(b) === Left(b)', function () {
var i = 33;
var a = new index_1.Right(33);
var f = function (a) { return new index_1.Left(a * 2); };
expect(a.flatMap(f)).toEqual(new index_1.Left(i * 2));
});
test('Law: Left.flatMap( f:(a) => Left(b) === Left', function () {
var i = 33;
var a = new index_1.Left(i);
var f = function (a) { return new index_1.Left(a.toString()); };
expect(a.flatMap(f)).toEqual(new index_1.Left(i.toString()));
});
});
describe('Extra None test cases ', function () {
var e_3, _a;
var option = new index_1.Some(3).fmap(function (i) { return i * 2; });
console.log(option);
try {
for (var option_1 = __values(option), option_1_1 = option_1.next(); !option_1_1.done; option_1_1 = option_1.next()) {
var i = option_1_1.value;
console.log(i);
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (option_1_1 && !option_1_1.done && (_a = option_1.return)) _a.call(option_1);
}
finally { if (e_3) throw e_3.error; }
}
var failed = new index_1.Some(0)
.flatMap(function (i) { return (i === 0 ? new index_1.None() : new index_1.Some(1 / i)); })
.fmap(function (w) { return "inverse is " + w; });
console.log(failed);
var succeeded = new index_1.Some(10)
.flatMap(function (i) { return (i === 0 ? new index_1.None() : new index_1.Some(1 / i)); })
.fmap(function (w) { return "inverse is " + w; });
console.log(succeeded);
var either = new index_1.Right(25)
.fmap(function (i) { return (i > 20 ? true : false); })
.flatMap(function (t) { return (t ? new index_1.Right('Ok') : new index_1.Left('Fail')); });
console.log(either);
console.log(either.getOrElse('ww'));
var triplePlusF = function (a) { return function (b) { return function (c) { return a + b + c; }; }; };
var triplePlus = new index_1.Some(triplePlusF);
var a = new index_1.Some(2);
var b = new index_1.Some(3);
var c = new index_1.Some(4);
var d = new index_1.None();
var plusedA = triplePlus
.applyMap(a)
.applyMap(b)
.applyMap(c);
console.log(plusedA);
var ra = plusedA.get();
var plusedB = triplePlus
.applyMap(a)
.applyMap(b)
.applyMap(d);
var rb = plusedB.get();
var rc = plusedB.getOrElse(0);
console.log(ra);
console.log(rb);
console.log(rc);
});
//# sourceMappingURL=index.test.js.map