Skip to content

Instantly share code, notes, and snippets.

@jimmydivvy
Last active February 26, 2023 10:35
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jimmydivvy/6e42ed2e43014ef55382 to your computer and use it in GitHub Desktop.
Save jimmydivvy/6e42ed2e43014ef55382 to your computer and use it in GitHub Desktop.
Simple IO Monad example in Javascript
class IO {
// We construct the IO type with a thunk/callback that returns the value when called
constructor( fn ){
this.fn = fn;
}
// IO doesn't do anything until we explicitly call it.
run(){
return this.fn();
}
// Create a new IO value containing a thunk that calls the
// previous one and runs a translation on it
/// map :: IO a -> (a -> b) -> IO b
map(fn){
return new IO(() => fn(this.run()))
}
// Create a new IO value with a monadic bind. Similar to `map`, but
// the underlying function itself returns an IO that must be unwrapped as well.s
/// bind :: IO a -> (a -> IO b) -> IO b
bind(fn){
return new IO(() => fn(this.run()).run())
}
}
// Log a value to the console using the IO monad.
// Rather than performing the action directly, it returns
// an IO value containing a thunk that will log to the console
// when called.
function ioLog( message ){
return new IO( () => console.log(message));
}
// "Pure" takes a primitive value and lifts it into the IO monad
function ioPure(value){
return new IO( () => value );
}
// Ask a question and then return the response.
function ioPrompt(question){
return new IO( () => prompt(question))
}
// This example uses 'pure' to provide a starting value, but you can replace with 'ioPrompt'
// to request a value from the user.
ioPure(5) // Start with the number 5
.map( x => x * 2 ) // Double it
.map( x => x + 1 ) // Add one. (We not have `11`)
.bind( x => ioPure(100).map( y => // bind against another ioPure to simulate requesting data from somewhere.
x + y // Add the two values together to get 111
))
.bind( x => ioLog( x)) // Now we log the result to the console.
.run() // Run it. Nothing has happened until this, we just have a
// Chain of thunks/callbacks waiting to fire.
// Calling `run()` sets the whole thing into motion.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment