Skip to content

Instantly share code, notes, and snippets.

@duhduhdan
Last active May 11, 2017 18:08
Show Gist options
  • Save duhduhdan/40bc760dab740eb9d901ef84ce9e2d21 to your computer and use it in GitHub Desktop.
Save duhduhdan/40bc760dab740eb9d901ef84ce9e2d21 to your computer and use it in GitHub Desktop.
Experimenting with FP theorems
/**
* 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
@jnathn
Copy link

jnathn commented May 11, 2017

Wow this is really cool +1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment