In function1 the do
block in myfunc
is working in the list monad, because String
is really just [Char]
. In there, return True
just creates [True]
. When you do x <- return True
that "extracts" True
out of [True]
and binds it to x
. The next line show x
converts True
into a String "True"
. which being the return value the compiler value expects to see, ends up working fine.
Meanwhile in function2, the do
block in myfunc is also working on the list monad (for the same reason, String
being really [Char]
) but calls on getLine
which is only available in the IO
monad. So unsurprisingly, this fails.
-- EDIT 1
OP has added a function3
-- function 3
myfunc :: String
myfunc = do
x <- getLine
return (show x)
No this should not work for the same reason function2 fails.
-- EDIT 2
OP has updated function3 to fix a copy paste error.
-- function 3
myfunc = do
x <- getLine
return (show x)
This is mentioned in the comments, but for clarity sake, this works because, when the type information is unspecified, GHC makes it best inference and after seeing getLine
, it figures it’s IO String
which does provide getLine
.
Note - I wrote this answer with as casual a tone as I could manage without being wrong with the intention of making it approachable to a beginner level.
show x
is aString
, which is the same as[Char]
, so the types all match up when thedo
block is in the List Monad. Whereas that option isn't available in the second one, since the use ofgetLine
forces the Monad to beIO
. – Elongationx <- (return True)
wouldn't compile since then you essentially are saying this:(return True) >>= (\x -> _)
thus a lamba without a body which is not allowed. – Headreturn True
has type(Monad m) => m Bool
. GHC will, if possible, infer which Monadm
makes sense in context. When the return type isString
then onlym ~ []
can ever work. – Elongation