Skip to content

Instantly share code, notes, and snippets.

# richdouglasevans/monad.js forked from i-am-tom/monad.js Last active Nov 1, 2018

The Monad example from the Fantasy Land series.
 const Promise = require("fantasy-promises"); const daggy = require("daggy"); //- Regular `compose` - old news! //+ compose :: (b -> c) //+ -> (a -> b) //+ -> a -> c const compose = f => g => x => f(g(x)); //- `chain`-sequencing `compose`, fancily //- known as Kleisli composition - it's the //- K in Ramda's "composeK"! //+ mcompose :: Chain m //+ => (b -> m c) //+ -> (a -> m b) //+ -> a -> m c const mcompose = f => g => x => g(x).chain(f); const Compose = daggy.tagged("Compose", ["f"]); //- Remember, for semigroups: //- concat :: Semigroup s => s -> s -> s //- Replace s with (a -> a)... //+ concat :: (a -> a) //+ -> (a -> a) //+ -> a -> a Compose.prototype.concat = function(that) { return Compose(x => this(that(x))); }; //- We need something that has no effect... //- The `id` function! //+ empty :: (a -> a) Compose.empty = () => Compose(x => x); const MCompose = T => { const MCompose_ = daggy.tagged("f"); //- Just as we did with Compose... //+ concat :: Chain m //+ => (a -> m a) //+ -> (a -> m a) //+ -> a -> m a MCompose_.prototype.concat = function(that) { return MCompose(x => that(x).chain(this)); }; //- So, we need empty :: (a -> m a) //+ empty :: Chain m, Applicative m //+ => (a -> m a) MCompose_.empty = () => MCompose(M.of); return MCompose_; }; // OUR APP const rl = require("readline").createInterface({ input: process.stdin, output: process.stdout }); //+ prompt :: Promise String const prompt = new Promise(res => rl.question("> ", res)); //- We use "Unit" to mean "undefined". //+ speak :: String -> Promise Unit const speak = string => new Promise(res => res(console.log(string))); //- Our entire asynchronous app! //+ MyApp :: Promise String const MyApp = // Get the name... speak("What is your name?").chain(_ => prompt).chain(name => // Get the age... speak("And what is your age?") .chain(_ => prompt) .chain( age => // Do the logic... age > 30 ? speak("Seriously, " + name + "?!").chain(_ => speak("You don't look a day over " + (age - 10) + "!") ) : speak("Hmm, I can believe that!") ) // Return the name! .chain(_ => Promise.of(name)) ); //- Our one little impurity: // We run our program with a final // handler for when we're all done! MyApp.fork(name => { // Do some database stuff... // Do some beeping and booping... console.log("FLATTERED " + name); rl.close(); // Or whatever });
to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.