haskellmonad-transformershaskeline

Perform simple IO in Haskeline, inside InputT monad, without having to resort to unsafePerformIO


Given the proof of concept code below I'd like to be able to somehow perform my foo function with the ability to output the string Paul! and the possibility of getting its return value inside the InputT monad-transformer without using unsafePerformIO to remove the IO wrapper after runExceptT.

import Control.Monad.Except

import System.IO.Unsafe (unsafePerformIO)
import System.Console.Haskeline


type ErrorWithIO = ExceptT String IO


foo :: String -> ErrorWithIO String
foo "paul" = do liftIO $ putStrLn "Paul!"
                return "OK!"
foo _ = throwError "ERROR!"


runRepl :: IO ()
runRepl = runInputT defaultSettings $ loop


loop :: InputT IO ()
loop = do
    line <- getInputLine "> "
    case line of
        Nothing -> return ()
        Just input -> do return $ putStrLn "asd"
                         case unsafePerformIO $ runExceptT $ foo input of
                             Left err -> outputStrLn err >> loop
                             Right res -> do
                                 x <- outputStrLn . show $ res
                                 loop




main :: IO ()
main = runRepl >> putStrLn "Goodbye!"

Am I missing something obvious here?


Solution

  • Since InputT IO is a MonadIO, you can use liftIO with this type:

    liftIO :: IO a -> InputT IO a
    

    So,

    do ...
       x <- liftIO $ runExceptT $ foo input
       case x of
         Left err  -> ...
         Right res -> ...
    

    Alternatively, use Control.Monad.Trans.lift instead.