fmap :: (Functor f) => f a -> (a -> b) -> f b
bind :: (Monad m) => m a -> (a -> m b) -> m b
Functors simply map elements one-to-one, while monads map elements to new data structures, which have to be combined back to a single data structure.
However, it's good you mention the laws - it's certainly possible to define bind with the correct type but incorrect behavior. An example would be defining the List bind in a way that doesn't concatenate the elements in order.
The following is a really good reference for understanding not just the difference between functors, applicatives, and monads, but also why each is more powerful than the one before it.
https://en.wikibooks.org/wiki/Haskell/Applicative_functors#A...
Perhaps you mean that a data structure like a list which implements bind is a monad.
Based on what I am reading in your overall comment, a monad is not a class of data structures which implement bind. I italicized keywords which I found problematic in your first statement, noting that you used refers to, and not is. (It is likely that I am confused, but have been missing a clear definition of a monad like "a monad is ...". If the definition involves more terms needing definitions, a topological sort would help. :-)
But, honestly (my silly rules-lawyering aside), a monad "is" an endofunctor and two particular nice natural transformations that satisfy some coherence conditions. This is at the other extreme of the pedagogical utility/clarity scale, since it is the final (if opaque) answer to any definitional ambiguity.
Functors and applicative functors precede monads in (pretentious cough) modern Haskell pedagogy, as championed by the (thankfully non-pretentious) Learn You A Haskell, as well as the Haskell Wikibook. Reading the relevant chapters is a good start. :)
Why is that? Locked doors, headaches, and intellectual need: https://mkremins.github.io/blog/doors-headaches-intellectual... :-)
Not having used them, I'm still puzzled at _why_ I would need monads at all.
At this point, tutorials use examples like "like flatMap and Maybe in other languages!" which is even more confusing. Why do I need a monad then, if there are similar constructs in other languages that don't need the understanding of monad? Why the complexity? What do I get from monads?
Similarly, if I define a new data type, and realize that it can implement Monad (or more precisely: that it has a monad instance), then I'll be rewarded with a giant library of code that's already compatible with my new data type [1]. Monad is an especially interesting interface because (1) it turns out many things conform to it [2] and (2) it comes with a set of algebraic laws. There is some controversy over how strict we need to be about the algebraic laws, but in some sense the algebraic laws are part of why such a general interface can be meaningful at all.
So yes, it's true that Monad allows us to sequence effects in a lazy pure language, and that's important, but I think a more down to earth reason to be interested is that it allows for more code reuse [3].
[1] Some of the function defined in the standard library: https://hackage.haskell.org/package/base-4.9.1.0/docs/Contro...
[2] See the 'instances' section here: https://hackage.haskell.org/package/base-4.9.1.0/docs/Contro... These are just the instances in the standard library.
[3] It's also worth mentioning that Monad gets all the attention, but Haskell if flush with other mathematically inspired interfaces that are just as general.
Monads are a mathematical concept, like a ring. "Maybe" is a monad in whatever language you use it in, just like integers are a ring in whatever language you use them in. Pointing out that complex numbers, rational numbers, nxn matrices are all examples of rings and wrapping everything up into a type class doesn't add to the complexity of the language.
> Why do I need a monad then, if there are similar constructs in other languages that don't need the understanding of monad?
is that you usually don't.
Where I work, people use a handful of monads daily, but most people know the monad laws, nor do they need to.
But now that they know a few specific monads, the "why" of monads is really, well, we needed certain convenience methods (namely bind aka flatMap) to make using e.g. Maybe or promises not a huge pain. And we chose a uniform way to do it across different wrapper types, so that we minimize the cognitive overhead.
I don't have an intuitive grasp of the formal definition of monads, but some examples of things that I _think_ are monads (in Java ... sorry :/ it's all I work with these days):
* jOOQ [1]: you use it to build up a sequence of SQL statements with a pleasant chaining API, then execute the whole shebang * Promise/future chaining: you build up a sequence of promises that should apply in-order, then defer their execution until later (unless you use a language that performs a transformation at compile time which effectively does this for you). * Streams/optional mapping: you build up a sequence of functions that should apply in-order to every element in a potentially empty sequence (optional: a sequence of 0 or 1). * The builder pattern: you build up a sequence of property values, then (potentially) construct the entire object.
They remove the need to type the same shit over and over again. With a list monad you avoid having to write the loop constructs, for the Option/Maybe monad (optional value) you avoid having to write if/then/else, for the Either/Choice monad you avoid having to write if/then/else and manually propagating an error value on failure, for the State monad you avoid having to pass a context value through as an argument to every function, for the Try monad you get exception handling and error propagation like the Either/Choice monad, with the Writer monad you are able to do logging without a global logging system or having to manually pass through a logging context, etc.
Ultimately they're there to reduce boilerplate and to help write more composable and reliable code. There are other benefits, but this encapsulation and abstraction of common patterns is what most programmers strive for, no matter what language they use, so I feel it's important to put them in that context.
Let me give you a very simple example. I'm going to use C# because it's been a long time since I've done any Haskell and I'll probably get it wrong.
I'm going to create a monad called NoNull. If at any point it sees a value that is null then it will stop the computation and return without completing. It's a slightly pointless example because C# has the null propagating operator, but conceptually it should be easy for any programmer to grasp that using null is bad, so being able to 'early out' of a computation when you get a null value is desirable.
First I'll define the type:
public class NoNull<A> where A : class
{
public readonly A Value;
public NoNull(A value) =>
Value = value;
public static NoNull<A> Return(A value) =>
new NoNull<A>(value);
public NoNull<B> Bind<B>(Func<A, NoNull<B>> bind) where B : class =>
Value is null
? NoNull<B>.Return(null)
: bind(Value);
public NoNull<B> Select<B>(Func<A, B> map) where B : class =>
Bind(a => NoNull<B>.Return(map(a)));
public NoNull<C> SelectMany<B, C>(Func<A, NoNull<B>> bind, Func<A, B, C> project)
where B : class
where C : class =>
Bind(bind).Select(b => project(Value, b));
}
It's a class that has a single field called Value. The two functions to care about are: Return - Which constructs the NoNull monad
Bind - Which is the guts of the monad, bind does the work
Select and SelectMany are there to make it work with LINQ. I have implemented them in terms of Bind.As you can probably see Bind is encapsulating the test for null, and if null is found then the result is Return(null), it doesn't run the `bind` delegate.
Next we'll create some NoNull monadic strings:
var w = NoNull<string>.Return("hello");
var x = NoNull<string>.Return(", ");
var y = NoNull<string>.Return("world");
var z = NoNull<string>.Return(null);
The last one contains null, the bad value.I can now use those values like so:
var result = from a in w
from b in x
from c in y
select a + b + c;
Notice there's no checks for null, the monad does that work for us.In this instance, result.Value is equal to "hello, world".
Now if I inject a bad value into our monadic computation:
var result = from a in w
from b in x
from c in y
from d in z // <--- this is null
select a + b + c + d;
Then result.Value is equal to null and the `a + b + c + d` didn't run at all.The alternative is this:
string w = "hello";
string x = ", ";
string y = "world";
string z = null;
string result = null;
if (w != null)
{
if (x != null)
{
if (y != null)
{
if (z != null)
{
result = w + x + y + z;
}
}
}
}
Where the programmer constantly has to do the work that the monad will do for free. I've nested those if statements to try and give you the impression of what the series of 'from' expressions are in the example above (in Haskell it's known as 'do notation'). Each 'from' creates a context over the whole of the rest of the expression.For the avoidance of doubt about the nesting, I could have written it thus:
var result = w.Bind(a =>
x.Bind(b =>
y.Bind(c =>
z.Bind(d =>
NoNull<string>.Return(a + b + c + d)))));
Here [1] is an example of a Parser monad in action in C# (it's part of a parser that parses C# source that I use to generate API reference docs for my github projects [2]). This runs code 'in the gaps' between each 'from' statement. What it does in those gaps is check if the parser above it failed, and if so it bails out with an appropriate error message based on what it expected. But you don't see any if(result.IsFaulted) ... code anywhere, or maintenance of the position of the parser in the input stream, because that is encapsulated in the Parser monad. It makes the code very clear (I think) in that it's not cluttered with the regular scaffolding of control structures that you usually see in imperative languages.What's really quite beautiful about monads is the way they compose, and I think this is especially beautiful with parser combinators. A Parser<Char> which parses a single character has the same interface as a Parser<SourceFile> which parses an entire source file. Being able to build simple parsers and then combine them into more complex ones is just a joy to do. Clearly parsing isn't unique to monads, but there's an elegance to it (and monads in general) which I think is hard to resist.
[1] https://github.com/louthy/best-form/blob/master/bestform.cs/...
[2] https://louthy.github.io/language-ext/LanguageExt.Core/Langu...
Usually that "way" is a function called "bind" with signature:
(X[T], (T -> X[T]) -> X[T]
And that's really all there is to it.Monads are fundamental only in the sense that there happens to be a lot of things for which these structures are useful (lists, optionals, effect wrappers, ...).
That doesn't make sense to me. Let's say I have the list [5,3,4], to me that means each application returns a three element list [f(5),x,x], [x,f(3),x], and [x,x,f(4)] then the bind function takes these lists and turns them into [f(5),f(3),f(4)].
What makes this function a monad?
f x = [x, x*2]
f =<< [5, 3, 4]
join (fmap f [5, 3, 4])
join ([[5, 10], [3, 6], [4, 8]])
[5, 10, 3, 6, 4, 8]
So the pattern is fmap a function `a -> f b`; this leaves us with `f (f b)` so we flatten. You might notice that we could bind as often as we want since we always get a list of integers!For example, suppose you have a list of ints, and want to bind a function, show. We have types:
[5,3,4] :: List Int
show :: Int -> List Char
That is to say, [5,3,4] is a list of ints, and show is a function that takes an int and returns a list of characters.In this case, we would have
[5,3,4] >>= show
f(5) ++ f(3) ++ f(4)
['5'] ++ ['3'] ++ ['4']
['5','3','4']
where "++" is list concatenation. The idea here is that when we apply show, we get back 3 different Lists, and want to combine them into a single list.then bind is join(map(f, x))?
bind just seems like a terrible name.
For some reason Haskell users try to make things sounds as academic as possible.
Probably because Haskell ended up being the language for academics. If you want to do programming language research in an ML-type language use Haskell. If you want to make a product, use OCaml. Not entirely true, but pretty close.
>So bind is flat map in other languages.
In the case of a List, yes, but there are other datastructures that implement Monad. This type of thing happens a fair amount in Haskell. It is not that uncommon to see code like:
instance Monad List where
(>>=) = flatMap
That is to say, the implementation of the interface is just another function that has a more domain specific name.There are other monads with a bind that cannot be understood as flatMap.
For example, the Maybe datatype is Haskell's version of Optional. For example, if a variable is of type `Maybe t`, it either contains a single value of type t, or no value. It is common to use Maybe without using it as a monad. However, Maybe does implement the Monad interface. In this case, bind is defined as follows:
x.bind(f) =
if (x.hasValue()) then { return Just(f(x.value)) }
else { return Nothing() }
where Just and Nothing are two constructors of Maybe. If we view 'no value' as analogous to null, then this bind function is null propogation.For example the state monad is defined as
F(X) = S -> S*X
I.e., a value of type F(X) is a state transformer which takes a state argument of type S and produces the new state and a value of type X. In this case, bind is sequencing of state transformers.Using the state monad you can write code that looks like it uses a global variable of type S, while being completely pure which makes testing and refactoring easier, and of course doesn't pollute the rest of the program.
[1]: http://blog.sigfpe.com/2008/12/mother-of-all-monads.html
Various people seem to be arguing that "flatMap" only makes sense for Lists and similar containers, but I don't really see why. Yes, you have to broaden your notion of "flattening" to understand it, but I think that's a lot easier for people to learn than a "new" operation called "bind".
I've been using Scala for a while after learning Haskell first (and understanding monads), and I've noticed how much more easily people understand flatMap, even for e.g. Futures.
And I think expanding a concept which someone already comfortably understands is a lot easier than asking them to learn a new one, even if you say it's kind of similar.
And FWIW, I don't think "flatten" is particularly unintuitive name, even for the more abstract cases, because it's still f (f a) -> f a. The mental gymnastics here is understanding how a Functor can be more than just a container, and you kind of need to learn that anyway.
bind(list_of_xs, lambda x:
bind(list_of_ys, lambda y:
return(x+y)))
That's a list comprehension. You bind the monadic values (list_of_xs) to element values (x). On lines 2 and 3, you can think of x as a bound variable that was assigned to one of the elements of list_of_xs on line 1. Then we "assign" y on line 2, and it's in scope on line 3. "Assign" would have also been a decent name for it. It's way more intuitive for me to think of those three lines as assigning/binding x and y to be summed together, rather than thinking of one flatmap of a lambda to flatmap of a final lambda to a function. The abstraction of variable binding just fits.[5,3,4] becomes [f(5), f(3), f(4)], but f(x) must return a List. Those inner Lists are then concatenated.
When I say "original data structure", I mean the type of data structure is the same (in this case, List).
Although I recall monads need to satisfy certain laws, and I don't recall if Trees satisfy them or not. Just because something is a data structure does not necessarily imply it is a monad.
For example, List is a monad. Suppose we had a List of Ints, such as [5,3,4]. If we were to run bind over this list, we would need a function that takes an Int and returns a List of something. We could use "show", the function which converts Ints to Strings (a String is technically a List of Char. Since this is a List, we're good). If we call bind using [5,3,4] and show, we get ["5","3","4"] which are then combined to "534".
We can check with the interpreter (>>= is bind):
Prelude> [5,3,4] >>= show
"534"