do
a <- getData // this is a awaiting a future
b <- getMoreData a // this is looping a list
c <- getMoreData2 b // this is null checking
d <- getEvenMoreData a c // this is awaiting another future
print d
Monads' hell, isn't it ?do
a <- getData // this is a awaiting a future
b <- getMoreData a // this is looping a list
c <- getMoreData2 b // this is null checking
d <- getEvenMoreData a c // this is awaiting another future
print d
Monads' hell, isn't it ? getData >>= \a ->
getMoreData a >>= \b ->
getMoreData2 b >>= \c ->
getEvenMoreData a c >>= \d ->
print d
The type signature of the `bind`/`>>=` function requires that both sides be the same type of monad, so it won't actually typecheck unless all of the get data functions return the same type of monad (future, list, optional, etc).There's a number of ways to get around this in haskell (monad transformers, free/freer monads, etc) but they're all pretty complicated unless you're pretty familiar with the language.
(Disclaimer I'm probably a little wrong in my description - I'm still learning haskell)
I remember a co-worker finding some weird combination of old extensions which allowed you to do something gross-ish of this form. I've _never_ seen such a thing in real life.
The only practical issue that comes close to this is sometimes trying to figure out _what_ monad a particular `do` block is running with (my mental type inference falls short of the compiler's).
In a language with a less powerful type system, you could write the same information in comments, but then the compiler wouldn't warn you if you accidentally changed the side effects of a statement.