Skip to content

Instantly share code, notes, and snippets.

@jjant
Created April 13, 2018 23:58
Show Gist options
  • Save jjant/124ce1dc5c4d1aab4a7394f09b38ad54 to your computer and use it in GitHub Desktop.
Save jjant/124ce1dc5c4d1aab4a7394f09b38ad54 to your computer and use it in GitHub Desktop.
IO Monad implementation in javascript for pure IO.
const GET_LINE = Symbol('GET_LINE');
const PUT_LINE = Symbol('PUT_LINE');
const RETURN = Symbol('RETURN');
const NOTHING = 'NOTHING!!';
const unit = undefined;
// Primitive IO actions, these are pure functions.
const returnIO = a => ({
type: RETURN,
flatMap: f => f(a),
// Derived operations
map(f) {
return this.flatMap(x => returnIO(f(x)));
},
// Sequencing operator, (>>).
then(io) {
return this.flatMap(_ => io);
}
});
const putLine = s => ({
type: PUT_LINE,
flatMap(f) {
return {
...this,
next: this.next === NOTHING ? f(undefined) : this.next.flatMap(f)
};
},
// Derived operations
map(f) {
return this.flatMap(x => returnIO(f(x)));
},
// Sequencing operator, (>>).
then(io) {
return this.flatMap(_ => io);
},
// Internal data. NEVER TOUCH.
next: NOTHING,
toPut: s
});
const getLine = {
type: GET_LINE,
// Bind, chain, (>>=)
flatMap(f) {
return this.whatToDoWithLineRead === NOTHING
? { ...this, whatToDoWithLineRead: f }
: {
...this,
whatToDoWithLineRead: s => this.whatToDoWithLineRead(s).flatMap(f)
};
},
// Derived operations
map(f) {
return this.flatMap(x => returnIO(f(x)));
},
// Sequencing operator, (>>).
then(io) {
return this.flatMap(_ => io);
},
// Internal data. NEVER TOUCH.
whatToDoWithLineRead: NOTHING
};
// Impure functions. You should never have to use this in your code.
const runIO = io => {
switch (io.type) {
case RETURN: // Do nothing
return;
case GET_LINE:
const lineRead = execGetLine(io);
return runIO(io.whatToDoWithLineRead(lineRead));
case PUT_LINE:
execPutLine(io);
return runIO(io.next);
}
};
const execGetLine = _ => {
const val = prompt();
return val;
};
const execPutLine = io => {
console.log(io.toPut);
return unit;
};
// Example programs
const main = putLine("What's your name?")
.then(getLine)
.map(name => 'Welcome, ' + name + '!')
.flatMap(putLine);
// Actually executing programs, this will be done automatically for you in the future.
// runIO :: IO () -> IO ()
runIO(main);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment