Reputation: 329
I am trying to understand Monads in Haskell and during my countless experiments with code I have encountered this thing:
f2 = do
return "da"
and the fact that it doesnt want to compile with huge error regarding type. I think the only important part is this:
No instance for (Monad m0) arising from a use of return'
The type variable `m0' is ambiguous
So then I have changed my code to:
f2 = do
return "da" :: IO [Char]
And it worked perfectly well. But when I have tried to mess up a bit and change the type to IO Int it was an error once again. So why the type is "ambiguous" when it actually isnt? Also when I will add something before return like:
f2 = do
putStrLn "das"
return 2
Then I dont have to specify the type of return. So can someone explain me what is going on really? Also why is return outputting "da" in the first case? Not da without ""?
Upvotes: 4
Views: 6214
Reputation: 8409
When learning about monads it's helpful to expand them out manually yourself, for instance the simple example:
test0 :: IO String
test0 = do
a <- getLine
putStrLn a
return a
If we enable the language extension {-# LANGUAGE ScopedTypeVariables #-}
then we can annotate each of the lines in the monad with it's explicit type which will show the type of the return block.
{-# LANGUAGE ScopedTypeVariables #-}
test1 :: IO String
test1 = do
a <- getLine :: IO String
putStrLn a :: IO ()
return a :: IO String
We can also annotate the explicit type of the left hand side pattern matching which "extracts" from the monad context on the right hand side.
test2 :: IO String
test2 = do
(a :: String) <- getLine :: IO String
(() :: ()) <- putStrLn a :: IO ()
return a :: IO String
We can even expand out the do-notation into its constituting parts:
test3 :: IO String
test3 = getLine >>=
(\a -> putStrLn a >>=
\() -> return a)
Hope that helps build your monad intuition.
Upvotes: 4
Reputation: 53871
First let's just point out that
do
return a
Is exactly the same as
return a
Now, the problem is that return
has the type
return :: Monad m => a -> m a
And when you have a declaration like
foo = bar
where foo
has no arguments haskell makes it "monomorphic". The result of this is that Haskell can't guess what m
is and won't generalize it so you need an explicit type signature. The most general one is
f2 :: Monad m => m String
f2 = return "das"
But you could also use IO
or any other monad
f2 :: IO String
Finally, in your last example, since you're returning 2
, you'd have to give a type signature that indicates you're returning some sort of number, like
f2 :: IO Integer
Upvotes: 8
Reputation: 1622
This is known Monomorphism_restriction
Use signatures
f2 :: Monad m => m String
f2 = do
return "da"
or use language extension:
{-# LANGUAGE NoMonomorphismRestriction #-}
f2 = do
return "da"
to get valid code
Upvotes: 5