I'm not convinced English has a word or convenient phrase for "monad", and it doesn't strike me that "flatMap" is it. How do I "flatMap" Haskell's STM monad? Or a probability monad? (I know the mechanics of the answer, I am specifically referring to the English-induced intution.) I don't see the intuition being particularly correct; flatMap is really tied to List, which isn't a particularly great thing to be tied to since it isn't very used. List's monadic interface is cute for some little algorithms, sure, which makes it disproportionately appear in examples, but list's monad implementation has complexity O(m^n) (where m is the size of the lists and n the number of lists you're going to consider) and you need some algorithm that gives you some serious culling on that before it's practical for very much.
The same concepts apply. With an option type, flatMap can be defined in Scala Option[1] types as:
flatMap[B](f: (A) ⇒ Option[B]): Option[B]
For the empty option situation (None in Scala), the result is a None. For the populated case (Some in Scala), the result is what f produces when given the value contained in the original Option[A] type. Of course, f is free to produce a None for its result should it so desire.What makes Monads neat IMHO is that so long as the container type adheres to the Monad laws[2], then the developer can fully rely on the behaviour conforming to a common set of expectations.
Its tied to collections, not specifically to List. A number of (but certainly not all!) important monads are (or can be viewed as) collections, including Optional/Maybe (which can be viewed as a collection with cardinality restricted to being either 0 or 1.)
It's also impressive how much complexity arise from that notion of multiplicity.
Actually, it transcends collections in general. As others have noted, the term "flatMap" is the concatenation of "flatten" and "map." There are other containers which support flatMap and satisfy the Monad laws[1]. An example of one in Scala is the Future[2] type. It's flatMap is described as:
Creates a new future by applying a function
to the successful result of this future, and
returns the result of the function as the new
future.
Conceptually, this behaves similarly to how a flatMap for a collection type behaves. Due to the nature of the Monad laws[1], this similarity is to be expected.1 - http://eed3si9n.com/learning-scalaz/Monad+laws.html
2 - http://www.scala-lang.org/api/2.11.7/#scala.concurrent.Futur...
You are quite right that the "map part" of flatMap is Functor, as Monads are a model of Functor. IOW, if there exists a Monad for some container, then there also exists a Functor for it.
However, flattening in and of itself does not fully define the flatMap (a.k.a. "bind") part of a Monad. Its atomic use with the map operation is what makes flatMap/bind operations satisfy the expectations of the rules for being a Monad.
Flatten on its own is extremely useful of course. It's often used in definitions of Join type classes.
The rules for Monad are perfectly well-stated in terms of join—perhaps even better stated if you're one to like Category Theoretic diagram chasing.
For completeness, the forms I am aware of are (in no particular order):
* unit and flatMap
* unit and compose
* unit, map, and join
The valid form which you reference being a model of the last one.
AFAIK, for any container 'T' to be able to satisfy the Monad laws, at least one of the aforementioned three combinators must exist for the container.
All three of them must, actually, since if one of them exists, all of them do (and you can define the other two in terms of the one you know.)
What I mean when I say flatMap is tied to collections is in the same sense that I read the poster to whom I was responding when they said it was tied to list, that is, that the intuition that the name "flatMap" leverages is tied to that construct. Obviously, the operation* it describes is more general, but the farther you get from collections, the less useful the intuition that the name leverages is.
(Whether this is better or worse for comprehension than the Haskell style of naming Monads and other related constructs and their associated operations is endlessly debatable and highly subjective.)
data Fake a = Fake
which is trivially a monad instance Monad Fake where
return _ = Fake
Fake >>= f = Fake
yet it clearly contains nothing.Its several characters and syllables shorter, and doesn't appeal to an intuition which is distant from many of the productive uses of construct.
This seems to be the approach that Elm is taking. (Although they're reluctant to add monads at all since they take ease of use seriously.)
Perhaps "then" would work. JavaScript promises use it to good effect, and they're a monad.
(BTW, my own take on renaming a monad into something less scary is daisychain, or, slightly more to-the-point, chainable.)
(>>=) :: M a -> (a -> M b) -> M b
The `a` is bound in the second argument.Instead we get nice "English" names which only work for certain monad instances and fail to adequately describe others.
Elm uses "andThen" instead of "bind", which works pretty well for the monadic types in its core library. But you need to start stretching your imagination to see why "andThen" makes sense for other monadic types. Honestly, I'm fine with "andThen", especially in the context of Elm and the monads it implicitly uses. But in the wider world of programming where exotic but useful monad instances exist I'd rather stick to the most general name.
By the way, the more pressing reason for Elm not having monads is the fact that it doesn't have typeclasses (or a similar concept) and doesn't allow you to parametrize over higher-kinded types (like Maybe).
[0] https://news.ycombinator.com/user?id=coolsunglasses [1] http://haskellbook.com/
What you'll usually see people insist is to describe monads by their operations, rather than through metaphor. That is, a monad is a type parametrized by some other type, with the following two functions:
1) return :: a -> m a 2) (>>=) :: m a -> (a -> m b) -> m b
such that three laws hold:
a) return x >>= f == f x b) m >>= return == m c) (m >>= f) >>= g == m >>= (\x -> f x >>= g)
For monads in Haskell, this is the technically correct definition.
That said, most people will tell you the best way to understand monads is to look at a few basic monad instance implementations (Maybe, Either a) and program with them, slowly learning new instances.
That is, a monad is a type parametrized by some other type, with the following two functions:
1) return :: a -> m a
2) (>>=) :: m a -> (a -> m b) -> m b
such that three laws hold: a) return x >>= f == f x
b) m >>= return == m
c) (m >>= f) >>= g == m >>= (\x -> f x >>= g)> "just a monoid in the category of endofunctors"
In fact, even among people who DO know the category theory necessary to understand this expression it's considered a very obtuse and useless explanation. Especially in the context of Haskell.
As for good readable introductions, I consider Wadler's paper "Monads for Functional Programming" to actually be a pretty good introduction. Another good intro is "You Could Have Invented Monads! (And Maybe You Already Have.)" http://blog.sigfpe.com/2006/08/you-could-have-invented-monad...
Imagine if, when you first started programming, and you wanted to do something with numbers, and you found out that in your programming language, the way you did that was to use something they called "Integers" (I know, right? ridiculous). So you google "Integers" and you find https://en.wikipedia.org/wiki/Integer, which helpfully tells you
"In elementary school teaching, integers are often intuitively defined as the disjoint union of the (positive) natural numbers, the singleton set whose only element is zero, and the negations of natural numbers."[1]
And you get the impression that to add a couple of numbers together you're actually going to have to understand cardinality and group theory and so on.
That's kind of where we are with monads, with the insistence on the academic language.
Though it does suggest that I could have fun by persuading beginning programmers that to really grok text processing they need to start off with a thorough grounding in string theory.
[1] I checked with my son, who goes to elementary school. I'm not sure he even knows what a disjoint union is. I'll have to have words with the teacher.
"In mathematics, the quaternions are a number system that extends the complex numbers."
Naturals are a subset of integers. Integers are a subset of rationals. Rational are a subset of reals. Reals are a subset of complex numbers. The latter are a subset of quaternions. It's not difficult to construct each number system. If you look inside any undergrad math textbook, you'll find exact same writing style showcased in the Wikipedia article on quaternions.
We have to do better at finding a way to teach this stuff.
https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotati...
IME, that's not at all true; most of the theory-heavy sources I've seen are explicitly framed as alternatives to the large body of intuitionist tutorials that avoid theory almost entirely, focusing on a few popular applications (usually, collections and IO.)
It's better for people new to the concepts to realize that they don't understand than to incorrectly believe they understand (based on mediocre collection-oriented analogies).
2) there is a ton of (even predating our modern programming era) useful literature using proper names;
3) those proposed “non-confusing” names have zero meaning for a lot of monads/applicaties/… I feel like 99% who want whem have only seen containers.
1. Mapping - the same as what Functor/Mappable provides. We use this to "map" over a structure, producing a nested structure.
2. Flattening: we just built our nested structure, time to squash it again.
In types akin to templates,
Structure<A>
------------------------ (map something suitable over it)
Structure<Structure<B>>
------------------------ (flatten it)
Structure<B>
It's not a terrible name, but it probably doesn't help seeing the bigger picture either. "Flattening" a parser, a subroutine, an empty thing -- that's not really something very intuitive. join:: m (m a) -> m a
I have a parser of a single character and a way to generate new character parserschar :: Char -> Parser Char x :: (Parser Char) let y = fmap (char . toUpper) x :: (Parser (Parser Char))
It's a parser which creates a new parser out of the input it consumes.
I do think that fmap/pure/join is the easier to understand set of defining functions for monads.
f >=> g = \x -> f x >>= g
m >>= f = (f <=< id) m
join = (>>= id)
m >>= f = join (fmap f m)
So if you're focused on composing monadic operations, thinking about it in terms of >=> is often a good idea.If we called them "Mappable", "Applicable", "FlatMappable" (yuck), "AssociativeAppendableWithIdentity"... then there would be disagreement about whether some new construct "is really" Applicable. Is summation really "Appending"?
And these arguments are high stakes, because the most important thing about an interface is that it tells the user what they can expect. If I ask for an Appendable, and get something that doesn't follow the rules I think Appendable should have, then... whose code is broken?
In Haskell, it's entirely clear whether a new type "is really" a Monoid or Functor - does it obey the laws? Okay!
Whether "container" is a good way to think of Functor is recognized as a purely pedagogic question (not that there's never drama in pedagogy, but those people getting work done can opt out without worry that it will break their code when they try to interface with others).
apply(fun,args)
it's not much of a mental stretch to do apply([fun1,fun2], [arg_for_fun1,arg_for_fun2])
it's probably better to just suck it up and learn the precise terms though. a lot of hazy thinking can hide behind overloaded words.