在 Haskeline 中,在 InputT monad 中执行简单的 IO,而不必求助于 unsafePerformIO
Perform simple IO in Haskeline, inside InputT monad, without having to resort to unsafePerformIO
鉴于下面的概念验证代码,我希望能够以某种方式执行我的 foo
函数,能够输出字符串 Paul!
并有可能获得它的 return InputT
monad-transformer 中的值,而不使用 unsafePerformIO
在 runExceptT
.
之后删除 IO 包装器
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!"
我是不是漏掉了什么明显的东西?
由于 InputT IO
是 MonadIO
,您可以将 liftIO
与此类型一起使用:
liftIO :: IO a -> InputT IO a
所以,
do ...
x <- liftIO $ runExceptT $ foo input
case x of
Left err -> ...
Right res -> ...
或者,使用 Control.Monad.Trans.lift
。
鉴于下面的概念验证代码,我希望能够以某种方式执行我的 foo
函数,能够输出字符串 Paul!
并有可能获得它的 return InputT
monad-transformer 中的值,而不使用 unsafePerformIO
在 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!"
我是不是漏掉了什么明显的东西?
由于 InputT IO
是 MonadIO
,您可以将 liftIO
与此类型一起使用:
liftIO :: IO a -> InputT IO a
所以,
do ...
x <- liftIO $ runExceptT $ foo input
case x of
Left err -> ...
Right res -> ...
或者,使用 Control.Monad.Trans.lift
。