> Monads are not complicated. They are implemented as a typeclass with two methods, return and (>>=) (pronounced "bind"). In order to implement a Monad instance, these two functions must be defined in accordance with the arity described in the typeclass definition:
This is a great example of what I just said: it uses complex Haskell code and functions to describe a monad. If you already know what it assumes you know, you most likely already know what a monad is.
Monads are very simple. They just aren't easy because most people don't have the base of terminology. When you grok them you'll laugh because you'll realize how simple and powerful and obvious they seem in hindsight.
This is the reason so many people write monad tutorials after they learn them. It's actually really weird. Does anyone else have some examples of things they learned which seemed really difficult but turned out to be really simple in hindsight?
Sure: everything.
Everything is complicated until you learn it, and then it looks simple in hindsight.
You're just confirming what OP said: it's not easy to come across an article explaining monads or Haskell that doesn't implicitly rely on the fact that the reader already understands monads or Haskell.
Beautiful insight. I now realize that simple and complex are about the concept being learnt, and easy and and hard likely to be about the process of learning. There would be correlation in general, however, not always. :-)
I have seen many examples of things which are easy at the end, but the process of reaching there was hard, sometimes because of initial ignorance of my own or of mankind overall.
I wish I could take credit for this one! I learned the distinction from a (rather famous) Rich Hickey talk. [0]
I've had this happen for
- everything from linear algebra (at least 20 things) - all kinds of stuff from mathematical optimization - inequalities, which are really difficult until something "clicks" and then when to apply them becomes obvious, cauchy-schwartz and jensen's in particular - induction (this was a long time ago / early in my math career) - diagram chases - the entire typeclass stack from FP (functor applicative monad, then all the monad interfaces) - huge chunks of axiomatic probability and measure theory (what do sigma algebras really mean, what is a good definition for integration, what is continuity of measure, dinkin's pi-lambda theorem) - and so it goes on
I am still waiting on some of the following things to click so that I may abuse them productively as well:
- LLL - yaos min-max theorem - lots of results from logic
I surmise this happens for monads and freaks developers out because it's one of the few pieces of serious math (i.e. no handwaving, given as a rigorous construction, etc) most people come across, so the phenomenon catches people off-guard.
If you like this thing, do more math!
things that are very similar to other things when expressed concretely, but actually exist at different levels of abstraction? things that are counter-intuitively awkward to express by way of examples, because too many things are examples, sometimes in multiple subtly different ways?
adjunctions (etc.) in category theory seem like 'above paragraph : the movie', but i can't claim to understand them in full generality so i'm unsure.
Yeah, we don't care for simple. Can you explain them in an EASY way?
No, as someone who understands monads (and not thanks to the explanations usually given) the real problem is that most explanations are crap and needlessly complicate the matter. Including every one I've read thus far (well, up to when I made my comment) in this thread.
It's as if they can't lay off Haskell notation and concepts for a moment to give people the overall picture. People, stop mentioning "functors", "monoids", ">>=", "bind" etc in your Monad explanations. Also drop the Haskell function definitions.
Even fmap shouldn't be taken for granted (as something already known) in a Monads explanation. Just describe what it does, giving a simple example. And when talking to Javascript programers use types and names of types that they already know, such as "array", not List. Even such simple terminology distinctions like those matter.
>They see the superficial similarities between Haskell and other languages but fail to grasp the more significant differences: higher-kinded types and type classes.
The whole magic of explaining is to give an idea of the "significant differences" without requiring any foundation beyond what an average blub programmer already has.
I'm a pretty good developer, and my language skills are all over the place. I did a lot of Scheme and Lisp early on. I used to try all the turing tarpit languages. I do mostly C++ and Java systems work now. And my current learning is Go and Rust. I've literally written my resume in PostScript years ago, and I still use APL-derived languages. I read and learned lambda calculus over a cross country business trip even.
And even with this background I find Haskell at times inscrutable, more often than not because somebody is trying to give me a description filled with unknown terminoligy and lines of Haskell itself I have no idea what it means.
There concepts aren't foreign to every other languages. Show them to me in pseudo-lisp, and I'm sure I'll do a pretty good job of picking them up. It looks like you could even describe monads in C by passing around opaque pointers, with some caveats.
That's like saying a giant, complex library with a nice, tight API is 'simple'. It's not, the complexity is just hidden.
Same thing with monads. Once you understand some of the machinery of category theory, or really grok functional programming, then yes, monads are 'simple', but all the complexity lies in getting there.
There are lots of things that are simple to state, like the fundamental theorem of algebra, but the machinery behind it is complex.
Haskell is a fairly simple language, but it very difficult to learn compared to a language I would consider much more complex like Java, because you cannot reuse as much of what you have learned from other languages. All the monad implementations are just a few simple lines of code, and understanding monad is just a matter of reading a few, reading the rules, and doing enough with them until their utility clicks. However, the type of abstraction they are and the way they are used are very different from the programming you are used to that they seem harder to learn.
I hold the opinion that complicated things can never be truly easy: they can only have the appearance of ease until there comes a time that you must understand all the complexity.
My favourite monad explanation is Tikhon Jelvis's at https://www.quora.com/What-are-monads-in-functional-programm..., but reading through it, it does assume some prerequisite knowledge about Haskell.
Monads can be two things: (1) a concept in category theory, (2) a rough implementation of that concept in a programming language.
If you want to learn about monads from the category theory perspective, great! This is really hard though, I wouldn't recommend it for most people (and haven't really even succeeded myself).
If you want to learn about a specific programming language's implementation of monads, you will naturally have to know how that language works. This road is far easier than category theory, but still requires knowing (for Haskell) what a typeclass is, what a higher-kinded type is, etc.
It sounds like you want an explanation without prereqs from either category theory or Haskell. If you google for monad tutorials you will find dozens of quick explanations, but I personally don't think this is a good way to actually understand them.
You can do that with the y-combinator but why not monads?
http://www.kylheku.com/cgit/lisp-snippets/tree/monads.lisp
Apologies for there not being a use example for the state transformer monad/comprehension. I can whip one up if needed.
You need types. Then you need "higher order types" or parameterized types. Then you need a way to discuss a common set of operations which appear repeatedly for some of these parameterized types and it can't be OO-like.
You can exemplify the operations in, e.g., Lisp, but you have a hard time "talking about" the thing.
---
In Scheme, monads are the answer to the following question:
The functions (define (pure a) (list a)) and (define (join ls) (foldl append (list) ls)) are related to lists in the same way that (define (pure a) (lambda (k) (k a))) and (define (join z) (lambda (k) ((z k) k))) is related to CPS-transformed programs. What is the commonality?
I'm not even saying that a bit sarcastically. I've read countless "tutorials" and even tried messing around with Haskell in an attempt to grok monads. According to the link shared by GP comment, my understanding is still completely wrong.
There is a reason there is a joke about it.
"A monad is just a monoid in the category of endofunctors, what's the probleⅿ?" - James Iry, taken from [0]
[0] http://james-iry.blogspot.com/2009/05/brief-incomplete-and-m...
You take a c++ parent class with two virtual methods. These methods are "return" and "bind". In order to implement a monad instance you must derive from this parents class and implement the virtual methods.
return takes a value and returns an instance of your template class containing the value.
bind takes an instance of your (template class A) a function of (type a ) to (template class B) and produces a value of (template class B).
If you don't care about the "laws" your definitions are expected to follow thats it.
The idea bind is you take a value of a template class such as (std::vector<Int> type) the value {3}, then based on value either pass it to the next function or return it.
one definition of bind would be if the vector is empty return it, if its not empty pass it to this function and return the result of that function.
return is just a way of placing a value into your template container class.