Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 601
Paul Avatar asked Jan 20 '15 19:01

Paul


People also ask

What is IO Monad in Haskell?

The I/O monad contains primitives which build composite actions, a process similar to joining statements in sequential order using `;' in other languages. Thus the monad serves as the glue which binds together the actions in a program.

How does Haskell handle IO?

Haskell separates pure functions from computations where side effects must be considered by encoding those side effects as values of a particular type. Specifically, a value of type (IO a) is an action, which if executed would produce a value of type a .

How is Haskell IO pure?

Haskell is a pure language Being pure means that the result of any function call is fully determined by its arguments. Procedural entities like rand() or getchar() in C, which return different results on each call, are simply impossible to write in Haskell.

What is Liftio?

A Monad that can convert any given IO[A] into a F[A] , useful for defining parametric signatures and composing monad transformer stacks.


1 Answers

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.

like image 100
chi Avatar answered Sep 19 '22 18:09

chi