3 ms·
Having also struggled with Monads before having an aha! moment, I've tried on occasion to help boil it down for those on the search for understanding. The hard
by michaelsbradley 12y ago
Having also struggled with Monads before having an aha! moment, I've tried on occasion to help boil it down for those on the search for understanding.
The hardest thing to get is that Monads aren't quite as "tangible" (not sure of a better word) as concepts like variable, object, property, instance, function, method. They are essentially relational and require something of a mental leap akin to coming to grips with how JavaScript's event loop is bound up in the control flow of your code, which otherwise proceeds from top to bottom of a .js file; or the rules governing closures and asynchronous function evaluation in this or that language.
The following is reprised from one of my HN comments in 2013.
-------
Monads are programming patterns which relate a set of values to a set of of functions – that's pretty much it! For any monad X, we can say that a function is monadic if it returns a value in the X Monad. The set of values are precisely those such that the following three Monad Laws[1] hold:
[ Using JavaScript syntax, they can be approximated as... ]
Left Identity
mBind( mReturn(a), f ) == f(a);
// => true
Right Identity
mBind( mReturn(a), mReturn ) == mReturn(a);
// => true
Associativity
mBind( mBind( mReturn(a), f ), g ) == mBind( mReturn(a),
function(a) {
return mBind( f(a), g );
} );
// => true
Above, `a` is (basically) any value, while `f` and `g` are any monadic functions for the same Monad. The definitions of `mBind` and `mReturn` will vary depending on the Monad, but the same laws (and sometimes additional properties) hold for each group of things taken as a whole – the monadic values, monadic functions, and the `mBind` and `mReturn` pair for those values and functions.
As you can see, there is nothing special that requires a statically typed language. That being said, if your language is statically typed, and even more so if its type system has advanced capabilities (e.g. Haskell's type system), then the relationships between the monadic values and functions can be leveraged to do a number of useful things, e.g. catching a host of bugs at compile time (though that's true regardless of Monads).
If your language is dynamically typed, then you won't get those extra benefits, but you can still take advantage of the fact that Monads can abstract away a great deal of plumbing between various pieces of your program.
Sometimes the Monad patterns will appear in a language under another name, or will be used "under the hood" to implement a particular API. Clojure/Script's `let` for example is essentially the Identity Monad; and its `for` is very much akin to the List Monad (the same is true for list comprehensions in other languages). The core.async library involves an inspiring application of the State Monad pattern[2].
[1] http://en.wikipedia.org/wiki/Monad_(functional_programming)#Monad_laws http://en.wikipedia.org/wiki/Monad_(functional_programming)#...
[2] https://github.com/clojure/core.async/blob/master/src/main/clojure/clojure/core/async/impl/ioc_macros.clj#L56 https://github.com/clojure/core.async/blob/master/src/main/c...
[&] https://github.com/clojure/core.async/blob/master/src/main/clojure/cljs/core/async/impl/ioc_macros.clj#L46 https://github.com/clojure/core.async/blob/master/src/main/c...
- StavrosK 12y agoI read your explanation, but couldn't make any sense of it. To begin with, you completely lost me in the second sentence: > For any monad X, we can say that a function is monadic if it returns a value in the X Monad. You're defining a monad by using itself in the definition! A definition is recursive if it recurses. I sort of understand the three laws after that, but it's like someone asking "what are operations on numbers" and getting the answer "operation is any operation that's associative, commutative, etc". It does nothing to explain monads to me, it just tells me that a monad is any thing that obeys three things. That information is completely useless to me.
- wz1000 12y ago> You're defining a monad by using itself in the definition! A definition is recursive if it recurses. The parent is not defining a monad with that sentence, he is defining what a monadic function is given that you have something that behaves like a monad > I sort of understand the three laws after that, but it's like someone asking "what are operations on numbers" and getting the answer "operation is any operation that's associative, commutative, etc". It does nothing to explain monads to me, it just tells me that a monad is any thing that obeys three things. That information is completely useless to me. The thing is that there is not much more to a monad than those three laws and the two functions(return and bind/join). Nonads are remarkable because lots of things happen to behave like monads(i.e have return and bind defined in a way that follows those operations). This includes interpreters, actions with side affects, non deterministic computations, computations with the possibility of failure and many other things. Monads are useful because they let you write code that is reusable across all monads and not just the one you happen to be coding for. If you look at code that is written like this, after enough experience you will get a vague idea of what it does, but its actual function will almost completely differ based on what kind of monad you use it for. This gives you a great amount of flexibility and refactorability as you can tweak and extent monads or create entirely new monads while still having this great mass of reusable code already written for you to use. Like the OP says, a monad is not some tangible concept like an object or a function. It is a concept that groups other concepts together. To learn about monads, you have to look at specific examples like the List monad, or the State monad or the IO monad. But there is no general explanation of a monad any more tangible than what the parent said.