I would like to read an input string with a custom prompt, however the prompt string comes from impure context, thus I can't use readInputLine
as is. I've tried to implement a function based on this answer
getLineIO :: MonadException m => IO String -> InputT m (Maybe String)
getLineIO ios = do
s <- ios
res <- getInputLine s
lift res
but I get an error
Couldn't match expected type ‘InputT m String’
with actual type ‘IO String’
Relevant bindings include
getLineIO :: IO String -> InputT m (Maybe String)
(bound at Main.hs:38:1)
In a stmt of a 'do' block: s <- ios
In the expression:
do { s <- ios;
return $ getInputLine s }
Update: got it to work based on @bheklilr's answer
getLineIO :: (MonadException m, MonadIO m) => IO String -> InputT m (Maybe String)
getLineIO ios = do
s <- liftIO ios
getInputLine s
The code
do
s <- ios
res <- getInputLine s
lift res
Gets de-sugared into
ios >>= \s -> (getInputLine s >>= \res -> lift res)
Where
(>>=) :: Monad m => m a -> (a -> m b) -> m b
This type signature means that m
has to be the same Monad
instance throughout. You've given it ios :: IO String
and \s -> getInputLine s :: String -> InputT n (Maybe String)
, but m
can't be both IO
and InputT n
, hence the compiler error.
You can just use liftIO
on ios
provided instance MonadIO m => MonadIO (InputT m)
is defined, which it is. So you can just do
getLineIO :: (MonadException m) => IO String -> InputT m (Maybe String)
getLineIO ios = do
s <- liftIO ios
res <- getInputLine s
lift res