If you are using functional , whether using a real functional language or any language that supports first-class function, you may have already used monads at some point. Most people just didn’t know they are monads. In this article, I am going to explain what is monad without using any mathematical theorem. Even more, I will demonstrate how to derive monad by only using plain . programming JavaScript WARNING: This is an advanced topic. May not suit for beginner.DISCLAIMER: This article won’t provide the exact definition of monad. So don’t read it if you have an exam about monad. I have been learning Haskell for about half year. I like to watch conference/meetup videos from youtube. One day, I watched a video called “Let’s be mainstream!”, in which the ELM creator, Evan Czaplicki, said “monad is callback”. I thought I understood what is monad that time, but I couldn’t figure out why Evan said that. Here is the link to that video, you can check after you finish this article if you want. Several weeks passed, after reading lots of learning materials, especially after watched “Why Do Monads Matter” by Derek Wright. In this video, he demonstrate several different monads by trying to solve one problem: function composition. The follow explanation basically use the same concept, but I’m going use JavaScript instead of Haskell. So first, as a functional programmer, we all know function composition, which is very very easy, like this: The composition function is very easy, it takes two arguments and , and return a new function which return the result value after applying then . And we can use this function to combine and to form the new function . composeF f g g f mul3 add1 addOneThenMul3 Now, assume we have a scenario: What we have: Two files, first file ( ) contains the path pointing to second file ( ), and second file contains the real content we want. file1 file2 A read file function Next, we need to construct the function to fetch the “real content”. The readFileSync is a synchronous IO function, which takes a path string as a input and return content of that given path in string. So we can reuse to compose the function we want: . composeF readFileContentSync So far so good! But what if the readFile function is asynchronous? If you are familiar with Node.js, then you probably have used callback to do flow control, which has a formal name: continuation-passing style or CPS. _In functional programming, continuation-passing style ( CPS) is a style of programming in which control is passed…_en.wikipedia.org Continuation-passing style Then the function will look like this: readFile Now, here is a problem: We cannot use c_omposeF_ to do function composition. Because this time, the function doesn’t return anything. But wait, we can still do function composition as long as: The derived function takes the same input as the first function, and It does what those functions do in sequence. All we need is a new composition function: Notice that: I changed the arguments’ sequence: from to . (f, g) (g, f) You can see, c_omposeCPS_ will return a new function which will call and in the callback of , call , and call with the the result value of in the end. g g f cb f Hooray! we can do function composition again! Ok, let’s try something interesting. First, we adjust the function signature of into : readFileCPS readFileHOF const readFileHOF = path => cb => {readFileCPS(path, cb)} HOF stands for Higher order Function. We just break one set of arguments into two set of arguments. Which makes takes a argument and returns a function which take as input, and the real function body will execute after all arguments set. readFileHOF path cb And then, we need a new composition function. Which is almost the same with , not so different. composeCPS Secondly, we give a name to the function which take as argument, and put it into an object, like this: cb Also, because we change the function signature again, so we need to adjust the composition function: Which is actually, again, not so different from , right? composeHOF We hate Repeat Yourself. So let’s create a helper function: const createExecObj = exec => ({exec}) This function returns an object with field, which is also a function. Let’s call the “object with field” exec exec ExecObj also make two line shorter: createExecObj readFileEXEC const readFileEXEC2 = path => {return createExecObj(cb => {readFileCPS(path, cb)})} After this change, you can see takes a path and return an exec object. Other than that, everything is the same. readFileEXE2 Next step, we are going to have a big change, so BE AWARE! So far, the both arguments of composition function are functions. Let’s change the first argument to something else: the exec object! We rename the to . This function will return a new exec object. If anyone call of this object, then it will do the same thing to and then in the callback, it uses . Notice that line 4 of this gist is the same as the line 6 of . compose bind bind exec execObj f composeEXEC Then the magic start: const readFile2EXEC2 = bindExec(readFileEXEC2('./file1'),readFileEXEC2)readFile2EXEC2.exec(result => console.log(result)) Not clear enough? Let’s remove the constant: bindExec(readFileEXEC2('./file1'),readFileEXEC2).exec(result => console.log(result)) Still don’t get it? Well, we’re almost there, be patient: Let’s try to “inline” the function to the exec object, like this: bindExec Please compare this with . The return object is the exec object, so we simply replace the with . Of course, because of the same reason, we don’t need first argument (line 3) bindExec execObj this So how to use it? readFileEXEC2('./file1').bind(readFileEXEC2).exec(result => console.log(result)) Do you see that? Something very familiar? No? Ok! Let’s do some rename: readFileEXEC2 -> readFileAsync bind -> then exec -> done readFileAsync('./file1').then(readFileAsync).done(result => console.log(result)) Oh my god! This is a promise!!!(Not exactly. Because promise will execute whether you call ) done. Or readFileEXEC2 -> readFile$ bind -> flatMap exec -> subscribe Oh my god! This is Rx!!!(Yes! almost! Of course we still need to add error handling and other stuff) So where is monad? The answer is: from until here. They are all monads!!! Specifically: composeCPS The becomes a monad because of . Actually, it is called readFileCPS composeCPS Cont monad in Haskell The “exec object” becomes a monad because of . Also, it is called IO monad in Haskell, check bind File IO in Haskell So how to identify whether a thing is a monad? Well, first, maybe you’re asking a wrong question. Instead of asking “Is it a monad”, you should ask “Can it be a monad”. What properties does a monad have? It has a context with a value. The value doesn’t have to exists. It provides a way to get the value (usually by callback) A function which able to pull the value out from the the monad (first argument) and put that value into another function as argument. ( should be a function that return a monad). And the returned value of function should be the same type of the first argument. bind f f bind The function often also named bind flatMap So monad is for async operation? NO!!! For example: Check with those properties: Yes! Square bracket [] is context. It’s ok to exists. By . forEach Because will return nested array (line 14), so map is not conform 4. We need to create a function. map flatMap As 4. So yes, array can be a monad. Is it necessary to understand what is monad in order to work? No! For example, lots of developers using array, promise and Rx without understand monad. It’s OK. So did I. I used Rx for a long time without really understand monad. But still, it is helpful if you want to create a tool like Rx. (Well, we just did it :p) Conclusion So “Monad is Callback“? Yes! According to property 3. Then “Callback is Monad”? Not yet! Only if there is a function defined. bind Thanks to , , to for reviewing this article. Tom Chen Guan-Yu Pan Wu, Ching Ting UPDATE: fix wrong wording: passion => patient, thanks to UPDATE: rename readFileFluent, thanks to Ian Hofmann-Hicks wkliang