2
votes

How come the following

foo :: MonadIO m => m ()
foo = print "hi"

causes the following error

Couldn't match type ‘m’ with ‘IO’ ‘m’ is a rigid type variable bound by the type signature for: foo :: forall (m :: * -> *). MonadIO m => m () at foo.hs:57:8 Expected type: m () Actual type: IO ()

As far as I know, shouldn't the MonadIO constraint allow this to work since IO () should be equal to a MonadIO ?

1

1 Answers

10
votes

IO is not equal to MonadIO.

MonadIO is a typeclass that, in plain terms, means that the monad in question can perform IO operations. In practice, since IO monad is "magic", this can mean only one of two things: the monad in question is IO itself, or the monad in question wraps IO in some way.

To express this idea of wrapping, the MonadIO type class has a method liftIO :: IO a -> m a, which lets you take an IO operation and "lift" it (or, if you prefer, "wrap" it) into the monad m, whatever that is.

So, to fix your code, all you need is liftIO:

foo :: MonadIO m => m ()
foo = liftIO $ print "hi"