-
-
Save spion/b433a665ca51d6c38e9f to your computer and use it in GitHub Desktop.
Future and ReaderT with auto-lifting and example
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
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))) | |
} | |
} |
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
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)) | |
} | |
} |
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
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)) | |
}) |
new
is not wasteful. Infact, doing it with closures would be a few times more expensive than new
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 ! )
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
Hey Spion !
Is it possible to create an implementation that uses partial functions and simpler objects rather than a lot of
new
andthis
and alsoclass
It seems really wasteful to do a
new
everytime you do achain
!Is it possible to just use Object construction and partial functions to make it easier to read and much more performant.