带有 IO 字符串的 readInputLine

readInputLine with IO String

我想读取带有自定义提示的输入字符串,但是提示字符串来自不纯的上下文,因此我不能按原样使用 readInputLine。我试图实现一个基于 this answer

的函数
getLineIO :: MonadException m => IO String -> InputT m (Maybe String)
getLineIO ios = do
    s <- ios
    res <- getInputLine s
    lift res

但是我得到一个错误

   Couldn't match expected type ‘InputT m String’
                with actual type ‘IO String’
    Relevant bindings include
      getLineIO :: IO String -> InputT m (Maybe String)
        (bound at Main.hs:38:1)
    In a stmt of a 'do' block: s <- ios
    In the expression:
      do { s <- ios;
           return $ getInputLine s }

更新: 根据@bheklilr 的

让它工作
getLineIO :: (MonadException m, MonadIO m) => IO String -> InputT m (Maybe String)
getLineIO ios = do
      s <- liftIO ios
      getInputLine s

代码

do
    s <- ios
    res <- getInputLine s
    lift res

脱糖成

ios >>= \s -> (getInputLine s >>= \res -> lift res)

在哪里

(>>=) :: Monad m => m a -> (a -> m b) -> m b

此类型签名意味着 m 必须始终是相同的 Monad 实例。你给了它 ios :: IO String\s -> getInputLine s :: String -> InputT n (Maybe String),但是 m 不能同时是 IOInputT n,因此编译器错误。

只要定义了 instance MonadIO m => MonadIO (InputT m),您就可以在 ios 上使用 liftIO,确实如此。所以你可以做

getLineIO :: (MonadException m) => IO String -> InputT m (Maybe String)
getLineIO ios = do
    s <- liftIO ios
    res <- getInputLine s
    lift res