Выполнять простой ввод-вывод на Haskeline внутри монады InputT, не прибегая к unsafePerformIO

Учитывая приведенный ниже код проверки концепции, я хотел бы иметь возможность каким-то образом выполнять свою функцию foo с возможностью вывода строки Paul! и возможностью получения ее возвращаемого значения внутри монады-преобразователя InputT без использования 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!"

Я пропустил что-то очевидное здесь?


person Paul    schedule 20.01.2015    source источник


Ответы (1)


Поскольку InputT IO является MonadIO, вы можете использовать liftIO с этим типом:

liftIO :: IO a -> InputT IO a

So,

do ...
   x <- liftIO $ runExceptT $ foo input
   case x of
     Left err  -> ...
     Right res -> ...

В качестве альтернативы используйте вместо него Control.Monad.Trans.lift.

person chi    schedule 20.01.2015
comment
Я уже пробовал это решение, но получаю ошибку компиляции: No instance for (MonadIO (InputT IO)) arising from a use of ‘liftIO’ - person Paul; 20.01.2015
comment
То же самое для простого решения lift: No instance for (MonadTrans InputT) arising from a use of ‘lift’ - person Paul; 20.01.2015
comment
@Paul Удивительно... вот у меня есть такой экземпляр. Может быть, вам нужно import Control.Monad.IO.Class ? - person chi; 20.01.2015
comment
@Paul Какую версию Haskeline вы используете? У вас установлено несколько версий некоторых пакетов? Это похоже на проблему клики. - person user2407038; 20.01.2015
comment
@Paul IIRC (большое, если), у меня была проблема с ошибками No instance ..., и она появилась после того, как я установил другой пакет Cabal. Попробуйте переустановить пакет Haskeline через Cabal (думаю, может быть опция --reinstall) и посмотрите, исправит ли это ситуацию. - person paul; 21.01.2015
comment
@Paul haskeline 0.7.1.3 здесь, кстати - person chi; 21.01.2015
comment
@Paul Я только что проверил свои заметки, и ошибка No instance ..., которую вы получали, была тем, что я получал. Я выяснил, что это начало происходить после того, как я установил библиотеку Lens, и что переустановка библиотеки Haskeline устранила проблему. - person paul; 21.01.2015
comment
@chi, Проблема решена, я попытался переустановить haskeline и скрыть его более старую версию (у меня как-то получилось две из них, 0.7.1.2 и 0.7.1.3). Казалось, это помогло. - person Paul; 21.01.2015