readInputLine с IO String

Я хотел бы прочитать входную строку с пользовательской подсказкой, однако строка подсказки происходит из нечистого контекста, поэтому я не могу использовать readInputLine как есть. Я пытался реализовать функцию, основанную на этом ответе

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

1 ответ

Решение

Код

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 не может быть и то и другое IO а также InputT nотсюда ошибка компилятора.

Вы можете просто использовать liftIO на ios предоставлена instance MonadIO m => MonadIO (InputT m) определяется, что это такое. Так что вы можете просто сделать

getLineIO :: (MonadException m) => IO String -> InputT m (Maybe String)
getLineIO ios = do
    s <- liftIO ios
    res <- getInputLine s
    lift res
Другие вопросы по тегам