4 ms·
I think a lot of people view monads as these esoteric things that provide some kind of FP enlightenment once you understand them when in reality, they're just a
by tmountain 8y ago
I think a lot of people view monads as these esoteric things that provide some kind of FP enlightenment once you understand them when in reality, they're just another layer in the list of abstractions one needs to understand to do "useful stuff" in a language like Haskell.
Without deep diving into a bunch of monad laws, etc, I think you can bring someone around to what a monad is at a basic level pretty quickly by explaining a few basic things.
1) There are values that can have multiple states. Example: a value of type Maybe could be represented as a "box" holding an underlying value (Just 3 or Just "Hello"), or it can be represented as the absence of a value (Nothing).
2) In OOP parlance, you can think of a functor as an interface with a single method (called fmap). Fmap takes two arguments: a normal function that takes a single value and returns a result and secondly a "boxed value". Fmap simply unwraps the boxed value, applies the function to the underlying result and then re-wraps the value and returns that wrapped value as the result. Fmap is smart enough that if you give it a value like (Nothing) it will simply return Nothing.
3) Monads take the functor mechanics a little further by applying a function that returns a "boxed" value to a "boxed" value. The same types of guarantees that a functor provides regarding handling states appropriately (give me Nothing, I will return Nothing) are baked in for you, which allows you to safely chain one call to the next without having to manually check for invalid data. This is done by a function called "bind" which is represented as the >>= operator in Haskell.
Take a contrived function "half" that returns its argument (x) divided by two if the argument is even or returns Nothing otherwise. A "boxed" value is returned in either circumstance.
half x = if even x then Just (x `div` 2) else Nothing
From here, you can chain calls to half without worrying about whether a previous computation failed.
Just 20 >>= half >>= half
(returns Just 5)
Just 5 >>= half
(returns Nothing)
Just 5 >>= half >>= half >>= ...
(also returns Nothing)
The Maybe instance of bind looks like this:
instance Monad Maybe where
Nothing >>= func = Nothing
Just val >>= func = func val
As-in, Nothing fed into a function, gives you Nothing back. Just <something> fed into a function gives you the result of the function applied to that value. IMPORTANT: the function returns a "boxed" value because that's what any subsequent call the bind (aka >>=) would expect.
Now imagine that this "off the books" computation can work with all sorts of "boxed" types beyond just Maybe. The additional work being done by each bind call happens independently of the function being provided to bind, so you can do things like logging how a result was calculated, build up stateful data structures, etc... having only written the code to do so one time.
There's clearly quite a bit more to know about monads and their applications, but I think the above is enough to get someone to understand some of the value they provide (at a very high level).
- mlevental 8y agoi don't know why you're getting downvoted because spelling out the pragmatics of monads using Maybe is exactly the right way to teach people about monads and gp is committing monad fallacy (though doing a nice job regardless of explaining to people like myself who already know a little) https://byorgey.wordpress.com/2009/01/12/abstraction-intuition-and-the-monad-tutorial-fallacy/ https://byorgey.wordpress.com/2009/01/12/abstraction-intuiti...
- tmountain 8y agoAgreed, in fact, I hesitated to even chime in because there's already so much "dust" around monads that I question the value in adding to the storm. That said, I think Steve Diehl has some great advice regarding understanding monads in his "What I Wish I Knew When Learning Haskell" document. Eightfold Path to Monad Satori Much ink has been spilled waxing lyrical about the supposed mystique of monads. Instead, I suggest a path to enlightenment: Don't read the monad tutorials. No really, don't read the monad tutorials. Learn about Haskell types. Learn what a typeclass is. Read the Typeclassopedia. Read the monad definitions. Use monads in real code. Don't write monad-analogy tutorials. In other words, the only path to understanding monads is to read the fine source, fire up GHC, and write some code. Analogies and metaphors will not lead to understanding.
- skybrian 8y agoI got it the second time, but then again I already knew the answer. A nit: "a value can have multiple states" seems a bit confusing when we're talking about immutable values? Perhaps start out saying something about union types instead?
- tmountain 8y agoAlready locked for editing. For anyone reading this after the fact, I'd restate as follows. There are types called Sum Types which are formed by combining other types. Each value associated with a Sum Type is associated with a constructor (label for the value) and zero or more values associated with that constructor. As an example, a Maybe type could be defined to represent two states as follows: data Maybe a = Just a | Nothing When a value is present, it can be represented as: Just 3, Just "Hello", Just [1,2,3], etc. While missing values can be represented as: Nothing And yeah to be clear, we are talking about immutable values. Boxes that carry around some value (or lack thereof) that never change.