haskellmonadshaskeline

Use the input from Haskeline's getInputLine


I have the code

 main :: IO()
 main = runInputT defaultSettings loop          
 where                                        
   --loop :: InputT IO ()                     
   loop = do                                  
     minput <- getInputLine "$ "              
     case minput of                           
       Nothing -> return ()                   
       Just input -> process $ words input          
     loop                                     

Where process has the type definition

process :: [String] -> IO ()

However I get the error:

• Couldn't match type ‘IO’ with ‘InputT m’                                                       
Expected type: InputT m ()                                                                     
  Actual type: IO ()                                                                           
• In the expression: process $ words input                                                       
In a case alternative: Just input -> process $ words input                                     
In a stmt of a 'do' block:                                                                     
  case minput of {                                                                             
    Nothing -> return ()                                                                       
    Just input -> process $ words input }

I was wondering if anybody could explain what I'm doing wrong. I just want to raw input from getInputLine to do other things with.

Thanks


Solution

  • All statements in a do block must have the same type (well, must have the same monad in their type). In your case, this is InputT IO something (with the monad being InputT IO).

    getInputLine "$ " has type InputT IO (Maybe String), so that part is OK.

    Then you have a case expression, which means all branches need to have the same type. The first branch is just return (), which gets the type InputT IO (). All good so far.

    The second branch is process $ words input. But this has type IO (), not InputT IO (), which is what the compiler expects at this point.

    To fix this: Fortunately there's an easy way to convert ("lift") a value of type IO x to InputT IO x, which is the liftIO function:

    Just input -> liftIO (process $ words input)
    

    That is, liftIO :: IO a -> InputT IO a (actually it's more general than that: liftIO :: (MonadIO m) => IO a -> m a but that doesn't matter here).