What is the difference between the two:
recompile :: MonadIO m => Bool -> m Bool
recompile :: Bool -> IO Bool
The types forall m. MonadIO m => Bool -> m Bool
and Bool -> IO Bool
are isomorphic:
{-# LANGUAGE RankNTypes #-}
import Control.Monad.IO.Class
from :: (forall m. MonadIO m => Bool -> m Bool) -> (Bool -> IO Bool)
from act = act
to :: (Bool -> IO Bool) -> (forall m. MonadIO m => Bool -> m Bool)
to act = liftIO . act
Not all types involving IO
are isomorphic to a version that replaces IO
with a constrained m
, though.
Generally, one uses MonadIO m
instead of m ~ IO
when they feel like scattering liftIO
through calling code will be annoying or when there are other mtl
-style constraints needed on m
; and uses m ~ IO
instead of MonadIO m
when going for simplicity of API (where MonadIO m
contributes to complexity and therefore is not desirable) or when dealing with forking or exception handling (where MonadIO m
is not possible for the reasons discussed in the linked question).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With