Reputation: 1521
{-# LANGUAGE NoMonomorphismRestriction #-}
module Try where
f :: IO (a -> IO String)
f = return $ const getLine
main :: IO ()
main = do
g <- f
:: IO (a -> IO String)
g "String" >>= print
g 5 >>= print
Even with the NoMonomorphismRestriction
flag and explicit type signature, this module fails to compile with Couldn't match expected type ‘[Char]’ with actual type ‘Int’
, despite g
being fully polymorphic.
Upvotes: 2
Views: 73
Reputation: 60513
This is not what the monomorphism restriction means. The monomorphism restriction says that if a definition has no type signature and has a left-hand side with no parameters, it will be specialized to a monomorphic type (or rather just monomorphic enough to get rid of any class constraints). You have given type signatures so it doesn't apply.
The problem here is that you have given the wrong type to f
.
f :: IO (a -> IO String)
actually means
f :: forall a. IO (a -> IO String)
That is, first pick a type a
, then you can bind to get a monomorphic function of type a -> IO String
for that a
. There is no trouble with this program, for example:
main = do
g <- f
g "String" >>= print
g' <- f
g' 5 >>= print
But your usage example requires this type:
f :: IO (forall a. a -> IO String)
That is, you want to bind first and pick the type later, i.e. use the function at multiple types. This is called an "impredicative type" and unfortunately GHC has not supported them for quite a while, as far as I know.
The way to solve this problem is to make a newtype
wrapper that explicitly quantifies the inner polymorphic type:
newtype R = R { getR :: forall a. a -> IO String }
f :: IO R
f = return $ R (const getLine)
main :: IO ()
main = do
g <- f
getR g "String" >>= print
getR g 5 >>= print
Upvotes: 6