Last active
March 14, 2018 09:42
-
-
Save abiodun0/b3068d30c35440b3828e433449268167 to your computer and use it in GitHub Desktop.
Reader Monad
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
// The advantage is that you can separate the “reading from configuration” part from the “doing stuff” part. | |
// Your “doing stuff” code needs not to be aware of the configuration that is being threaded through, | |
// but can still ask for values whenever necesary. | |
// it becomes more apparent once you start actually writing code. You can manually receive all your config whenever your main function is called, and take care of passing down those values manually so that they can always be reached even 5 function-calls deep. | |
// Eventually you are going to want to write some sort of abstraction over this “argument passing”, and | |
// if you do so, you will most likely end up writing your own Reader implementation | |
// wether you are aware of it or not | |
// Number -> Reader({db, logger}, Number) | |
const innerFn = val1 => | |
Reader.ask.map(({db, logger}) => { | |
const val3 = db.exec("SELECT val FROM table3"); | |
const val4 = val1 * val3; | |
logger.info("calculated inner value", val4); | |
return val4; | |
}); | |
// Transaction -> Reader({db, logger}, Number) | |
const middleFn = tx => | |
Reader.ask.chain(({db, logger}) => { | |
const val1 = db.exec("SELECT val FROM table1"); | |
const val2 = db.exec("UPDATE table2 SET val = ?", val1, tx); | |
logger.debug("executed queries"); | |
return innerFn(val1); | |
}); | |
const outterFn = () => { | |
const logger = createLogger(); | |
const db = createDbClient(); | |
return db.withTransaction(tx => middleFn(tx).run({db, logger})); | |
}; | |
function createLogger() { | |
return { | |
debug: x => console.log('log', x), | |
info: x => console.log('info', x) | |
} | |
} | |
function createDbClient() { | |
return { | |
exec: (...args) => (console.log('exec', ...args), Math.random() * 100), | |
withTransaction: cb => cb(42) | |
} | |
} |
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
function Reader(x) { | |
this.x = x; | |
} | |
Reader.prototype.run = function(env) { | |
return this.x(env); | |
} | |
Reader.of = function(x) { | |
return new Reader(() => x); | |
} | |
Reader.prototype.map = function(fn) { | |
return new Reader(env => fn(this.run(env))); | |
} | |
Reader.prototype.join = function() { | |
return new Reader(env => this.run(env).run(env)); | |
} | |
Reader.prototype.chain = function(fn) { | |
return this.map(fn).join(); | |
} | |
Reader.ask = new Reader(env => env); | |
Reader.of(2) | |
.map(x => x * 2) | |
.chain(x => Reader.ask.map(env => env + x)) | |
.map(x => x * 3) | |
.chain(x => Reader.ask.map(env => x - env)) | |
.run(3); // 18 |
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
const innerFn = (tx, db, logger, val1) => { | |
const val3 = db.exec("SELECT val FROM table3"); | |
const val4 = val1 * val3; | |
logger.info("calculated inner value", val4); | |
return val4; | |
}; | |
const middleFn = (tx, db, logger) => { | |
const val1 = db.exec("SELECT val FROM table1"); | |
const val2 = db.exec("UPDATE table2 SET val = ?", val1, tx); | |
logger.debug("executed queries"); | |
return innerFn(tx, db, logger, val1); | |
}; | |
export const outerFn = () => { | |
const logger = createLogger(); | |
const db = createDbClient(); | |
return db.withTransaction(tx => middleFn(tx, db, logger)); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment