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

1

7

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?

Alburga answered 20/1, 2015 at 19:22 Comment(0)
T
11

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.

Tillman answered 20/1, 2015 at 19:33 Comment(8)
I already tried this solution, but I get a compilation error: No instance for (MonadIO (InputT IO)) arising from a use of ‘liftIO’Alburga
The same for the simple lift solution: No instance for (MonadTrans InputT) arising from a use of ‘lift’Alburga
@Alburga Surprising... here I have such an instance. Maybe you need to import Control.Monad.IO.Class ?Tillman
@Alburga What version of Haskeline are you using? Do you have multiple versions of some packages installed? This looks like a cabal issue.Niece
@Alburga IIRC (a big if), I had the "No instance..." errors issue and it appeared after I installed a different Cabal package. Try re-installing the Haskeline package through Cabal (I think there might be a --reinstall option) and see if that fixes it.Bonanza
@Alburga haskeline 0.7.1.3 here, BTWTillman
@Alburga I just checked my notes and the "No instance..." error you were getting was what I was getting. I worked out that it had started happening after I'd installed the Lens library, and that re-installing the Haskeline library fixed the problem.Bonanza
@chi, The problem is solved, I tried reinstalling haskeline and hiding an older version of it (I somehow wound up having two of them, 0.7.1.2 and 0.7.1.3). This seemed to do the trick.Alburga

© 2022 - 2024 — McMap. All rights reserved.