To figure out what is going on, you can try de-sugaring you function:
main :: IO ()
main = getArgs >>= \ args ->
case args of
[] -> putStrLn "Give an argument!"
Here, getArgs
has type IO [String]
and the function (let's call it f
) has type [String] -> IO ()
. Now lets see what's going on with (>>=)
:
(>>=) :: m a -> (a -> m b) -> m b
-- a unifies with [String] and m with IO
(getArgs >>=) :: ([String] -> IO b) -> IO b
(>>=) :: IO [String] -> ([String] -> IO b) -> IO b
-- b unifies with ()
getArgs >>= f :: IO ()
(>>=) :: IO [String] -> ([String] -> IO ()) -> IO ()
For your example with C
, there are three things wrong:
- GHC expects
main
to have type IO ()
, but it has type C ()
in your snippet
getArgs
is expected to have type C [String]
, but it has type IO [String]
- same for
putStrLn
, which must have type C ()
To fix this, since ErrorT
is a monad transformer, you can lift
a monadic action to the level of the transformer with lift
.
liftIO
is a lift
operation that can be applied only with monad transforming IO
. The interesting thing is that it can work with any monad transformer (with as much monad transformer depth as you want): With liftIO
, you can work with T1 (T2 (... (Tn IO)...)) a
for any n
where Tn
are monad transformers.
You can notice their kind of similar signatures:
lift :: (MonadTrans t, Monad m) => m a -> t m a
liftIO :: MonadIO m => IO a -> m a
You don't need to specify IO for m, in the signature of liftIO
, because it's instance of MonadIO already tells us that it can perform only IO actions.
To conclude, this is how you would use liftIO
in your program:
type C = ErrorT String IO
main :: IO ()
main = runErrorT go >>= print -- print the result of type `Either String ()`
where go :: C ()
go = do
args <- liftIO getArgs
case args of
[] -> liftIO $ putStrLn "Give an argument!"
But, here, since you don't use any features of the ErrorT
monad, the code is not really a good example.
Also, note that if you are talking about ErrorT
in the mtl
package, it is deprecated, consider using ExceptT
.
Check out this post for more information about lift
vs liftIO