Last active
May 11, 2017 18:08
-
-
Save duhduhdan/40bc760dab740eb9d901ef84ce9e2d21 to your computer and use it in GitHub Desktop.
Experimenting with FP theorems
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
/** | |
* Future denotes a value that will occur after a certain amount of time | |
* Is a Functor: | |
* - type acting as context for other types | |
* - can apply normal function inside | |
* Is a Monad: | |
* - lifts a normal value to a Monadic one (Future.of) | |
* - chains 2 consecutive operations (Future.prototype.flatMap) | |
*/ | |
class Future { | |
constructor() { | |
this.slots = [] | |
this.failedSlots = [] | |
} | |
ready(slot) { | |
if (this.completed) { | |
slot(this.value) | |
} else { | |
this.slots.push(slot) | |
} | |
} | |
complete(val) { | |
if (this.completed) { | |
return | |
} | |
this.value = val | |
this.completed = true | |
// notify subscribers | |
this.slots.forEach(slot => slot(val)) | |
// discard | |
this.slots = null | |
} | |
failed(slot) { | |
if (this.hasFailed) { | |
slot(this.error) | |
} else { | |
this.failedSlots.push(slot) | |
} | |
} | |
fail(err) { | |
if (this.completed || this.hasFailed) { | |
throw 'Your future has already been decided!' | |
} | |
this.hasFailed = true | |
this.error = err | |
this.failSlots.forEach(fail => fail(err)) | |
} | |
map(fn) { | |
const future = new Future() | |
this.ready(val => { | |
try { | |
future.complete(fn(val)) | |
} catch(err) { | |
future.fail(err) | |
} | |
}) | |
this.failed(err => future.fail(err)) | |
return future | |
} | |
flatten() { | |
const future = new Future() | |
this.ready(secondFuture => secondFuture.ready(val => future.complete(val))) | |
return future | |
} | |
flatMap(fn) { | |
return this.map(fn).flatten() | |
} | |
} | |
// of : Value -> Future<Value> | |
Future.of = function(val) { | |
const future = new Future() | |
future.complete(val) | |
return future | |
} | |
// delay : (Value, Number) -> Future<Value> | |
Future.delay = function(val, ms) { | |
const future = new Future() | |
setTimeout(_ => future.complete(val), ms) | |
return future | |
} | |
Future.liftSingleArity = function(fn) { | |
return future => future.map(fn) | |
} | |
// liftDoubleArity : ((a, b) -> c) -> ((Future<a>, Future<b>) -> Future<c>) | |
Future.liftDoubleArity = function(fn) { | |
return (f1, f2) => | |
f1.flatMap(val1 => f2.flatMap(val2 => Future.of(fn(val1, val2)))) | |
} | |
module.exports = Future |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Wow this is really cool +1