Skip to content

Instantly share code, notes, and snippets.

@spion
Forked from robotlolita/0-specification.md
Last active June 26, 2016 20:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save spion/b433a665ca51d6c38e9f to your computer and use it in GitHub Desktop.
Save spion/b433a665ca51d6c38e9f to your computer and use it in GitHub Desktop.
Future and ReaderT with auto-lifting and example
class Future {
constructor(computation) {
this.fork = computation
this.__future__ = true;
}
static is(val) {
return (val != null && val.__future__ === true)
}
static of(value) {
if (Future.is(value)) return value;
return new Future((resolve, reject) => resolve(value))
}
static err(e) {
if (Future.is(e)) return e;
return new Future((resolve, reject) => reject(e))
}
chain(f) {
return new Future((resolve, reject) =>
this.fork(value => Future.of(f(value)).fork(resolve, reject), reject))
}
orElse(f) {
return new Future((resolve, reject) =>
this.fork(resolve, error => Future.of(f(error)).fork(resolve, reject)))
}
}
var ReaderT = (M) => class ReaderT {
constructor(computation) {
this.computation = computation
this.__reader__ = true;
}
static is(val) {
return (val != null && val.__reader__ === true)
}
runWith(data) {
return this.computation(data)
}
chain(f) {
return new ReaderT(data => this.computation(data).chain(a => ReaderT.of(f(a)).runWith(data)));
}
static of(val) {
if (ReaderT.is(val)) return val;
return new ReaderT(data => M.of(val))
}
static ask() {
return new ReaderT(data => M.of(data))
}
}
var fs = require('fs')
var readFile = path => new Future((resolve, reject) => fs.readFile(path, 'utf8', (err, res) => err ? reject(err) : resolve(res)))
var SuperFuture = ReaderT(Future)
var doStuffx = () => getUserId().chain(id => readFile(id + '.txt'))
var getUserId = () => SuperFuture.ask().chain(user => user.id)
// From the route handler, we only pass the user id once.
// It automatically propagates through the SuperFutures
app.get('/some/url', function(req, res) {
doStuffx().runWith({id: req.user.id}).fork(data => res.end(data), err => console.error(err))
})
@JoyKrishnaMondal
Copy link

Hey Spion !

Is it possible to create an implementation that uses partial functions and simpler objects rather than a lot of new and this and also class

It seems really wasteful to do a new everytime you do a chain !

Is it possible to just use Object construction and partial functions to make it easier to read and much more performant.

@spion
Copy link
Author

spion commented May 29, 2016

new is not wasteful. Infact, doing it with closures would be a few times more expensive than new

@JoyKrishnaMondal
Copy link

The more I read the code - the more it makes sense now - when I first gorked it I didn't use most.js for a practical project - but now it seems quite simpler. ( especially after seeing chain aka flatmap in action )

you chain function actually does two functions - map and join :) ( sorry to bring up Dr. Boolean ! )

@JoyKrishnaMondal
Copy link

wondering if could mix this with most.js streams - and how

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