Last active
October 27, 2016 14:27
-
-
Save gunar/8c6e0c3aa051b32091b7b37ab5f676c3 to your computer and use it in GitHub Desktop.
Algebraic Data Types
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Inspired by [Brian Lonsdorf - Oh Composable World! - YouTube](https://www.youtube.com/watch?v=SfWR3dKnFIo) | |
| // Inspired by [Mostly adequate guide to FP](https://github.com/MostlyAdequate/mostly-adequate-guide) | |
| const Box = function(x) { | |
| this.__value = x; | |
| } | |
| Box.of = x => new Box(x) | |
| Box.prototype.map = function (f) { | |
| return Box.of(f(this.__value)) | |
| } | |
| Box.prototype.chain = function (f) { | |
| return f(this.__value) | |
| } | |
| Box.prototype.concat = function (box) { | |
| return box.map(x => this.__value.concat(x)) | |
| // or | |
| return box.chain(x => Box.of(this.__value.concat(x))) | |
| } | |
| Box.prototype.ap = function (x) { | |
| return x.map(this.__value) | |
| } | |
| Box.prototype.reduce = function (f, acc) { | |
| const arr = [] | |
| for (let i = 0; i <= this.__value; i++) { | |
| arr.push(i); | |
| } | |
| return arr.reduce(f, acc) | |
| } | |
| Box.prototype.toString = function() { return `Box(${this.__value})` } | |
| console.log('Functor: ' + | |
| Box.of(20).map(x => x / 2)) | |
| // Box(10) | |
| console.log('Monad: ' + | |
| Box.of(true).chain(x => Box.of(!x))) | |
| // Box(false) | |
| console.log('Monoid: ' + | |
| Box.of('small').concat(Box.of('pox'))) | |
| // Box('smallpox') | |
| console.log('Applicative: ' + | |
| Box.of(x => x + 1).ap(Box.of(2))) | |
| // Box(3) | |
| console.log('Foldable: ' + | |
| Box.of(3).reduce((acc, x) => acc + x, 0)) | |
| // I needed to implement Either in order to try out Traversable | |
| // Either | |
| function Either(x) { | |
| this.__value = x; | |
| } | |
| Either.of = x => new Either(x) | |
| Either.fromNullable = function (x) { | |
| return x | |
| ? Right.of(x) | |
| : Left.of(x) | |
| } | |
| Either.prototype.toString = function() { return `Either(${this.__value})` } | |
| // Left | |
| function Left(x) { | |
| this.__value = x; | |
| } | |
| Left.of = x => new Left(x) | |
| Left.prototype.chain = function (f) { | |
| return f(this.__value) | |
| } | |
| Left.prototype.toString = function() { return `Left(${this.__value})` } | |
| // Right | |
| function Right(x) { | |
| this.__value = x; | |
| } | |
| Right.of = x => new Right(x) | |
| Right.prototype.map = function (f) { | |
| return Right.of(f(this.__value)) | |
| } | |
| Right.prototype.chain = function (f) { | |
| return f(this.__value) | |
| } | |
| Right.prototype.toString = function() { return `Right(${this.__value})` } | |
| Box.prototype.traverse = function (f, of) { | |
| return f(this.__value).map(of) | |
| } | |
| console.log('Traversable: ' + | |
| Box.of(3).traverse(Either.fromNullable, Box.of)) | |
| function eitherToBox(either) { | |
| return either.chain(x => Box.of(x)) | |
| } | |
| console.log('Natural transformation: ', | |
| eitherToBox(Either.fromNullable(null)).toString()) | |
| // Box(null) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
What's the theory behind the implementation of reduce there? For FL it's just:
Identity.prototype.reduce = function(f, acc) {
return f(acc, this.value);
};
There's also .fold as an alternative (which for Identity can be implemented as just an alias for .chain, but also has a binary implementation for Either to fold out of the type).
Once you have fold, you can create an eithertoBox that just does either.fold(Box.of,Box.of) (i.e. putting either the left or the right value in a box.) Using chain to remove things from a type is a bad idea (as it's not always, and often not just f(this.value), or alias to fold).