The problem is that you confuse wrapped monadic values with pure values.
The first thing to know is the designation of syntactic sugar for regular function calls ( >>= and >> ). This way, it helps to see what your desugars code is, too.
Let's try something simpler
fab = do one <- a + b return one
You have the same problem as your code, but easier. To understand why this does not work, we ask: what does it mean? Well, we can rewrite the <- character using >>=
fab = (a + b) >>= \x -> return x
(this is not the simplest view, but clearly indicates)
If you check the following in GHCi
>> :t (>>=) Monad m => ma -> (a -> mb) -> mb
that is, the function >>= takes: an argument of type m of a and a function from a to m from b and returns a m of b .
How about this code?
(a + b)
There will be a number. How about the other half
\x -> return x
Takes an object of type a and returns an object of type ma for any a
So, you need to have a number, this is also some kind of monad. Can you come up with something like that? It is not clear what it will be, which is the reason for the suspicion that this should introduce a check.
One good way to make peace with monads is to look at some specific examples.
Maybe monad expresses calculations that may fail
instance Monad Maybe where return = Just (>>=) (Just a) f = fa (>>=) Nothing _ = Nothing
This allows you to say things with a type such as
f args = do x <- functionThatMightFail args y <- anotherfunctionThatMightFail x return y
or the same code is easier
f args = do x <- functionThatMightFail args anotherfunctionThatMightFail x
or maybe
f args = functionThatMightFail args >>= anotherfunctionThatMightFail
On the other hand, the List monad captures the idea of performing the same function for each element of the list, and then combines the results together. There are many simple examples:
f = do x <- [1,2,3,4] [1..x]
If you understand these, play with the State monad. This will help you get a more general idea that "monads are computational models." Then I checked Parsec and, of course, IO