Let's say you need a function that maintains internal state. Now, in non-pure languages, you could that by simply referring to some global variable, but let's agree that's bad. So how can you model internal state purely?
Simple, your function takes the current state and produces a new state, along with its result. So, a pure function like:
f(String) => Int
turns into the stateful function: f(String) => (State => [Int, State])
I.e. a function that returns a function that takes in a state and produces a result and a new state.Cool, but now let's say we have another function g:
g(Int) => (State => [Double, State])
Let's now say we want to compose those two functions: let result = g(f("5"));
However, this won't work, becase f produces (State => [Int, State]) but g expects Int.So, here's bind for the State monad (implementation is not important):
bind(State => [a, State], a => (State => [b, State])) => (State => [b, State])
If we define a "type alias" (just a synonym, so we don't have to type that much) for a stateful function: type StatefulFunction<a> = State => [a, State]
and then replace the above bind definition with it: bind(StatefulFunction<a>, a => StatefulFunction<b>) => StatefulFunction<b>
you can see that is has the same structure as flatMap! flatMap(List<a>, a => List<b>) => List<b>
With the type alias, f and g would then look like this: f(String) => StatefulFunction<Int>
f(Int) => StatefulFunction<Double>
So now, here's how you compose f and g: bind(f("5"), a => g(a))
In Haskell, there's syntax sugar for bind, so the above turns into do
a <- f "5"
g a
which is very similar to a conventional language: {
a = f(5);
g(a);
}
EDIT: forgot result type in bind and flatMap.