2015-04-02 3 views
0

Я использую библиотеку MongoDB для обработки данных из Mongodb. Существует Монада, называемая Action, представляющая операцию чтения или записи БД https://github.com/TonyGen/mongoDB-haskell/blob/master/doc/tutorial.md. Но, я нахожу, что когда я в Monad Action, я также хочу сделать некоторые IO, которые должны быть в IO Monad. Некоторые коды, такие какКак использовать IO Monad в другой Monad

-- `Action' is a Monad 
-- 
intoFile :: String -> Cursor -> Action IO() 
intoFile ric c = do 
    outH <- liftIO $ openFile ric AppendMode 
    liftIO $ hPutStrLn outH "Some log" 
    loopIntoFile outH c 
    liftIO $ hClose outH 

Существует liftIO перед любой IO монады, и я думаю, что это может быть многословным. Любой краткий способ справиться с этим?

+2

Там ISN «Это действительно хороший способ справиться с этим, поскольку действия« IO »реализованы исключительно как возвращающие« IO a »вместо« MonadIO m => ma'. Я часто вижу такие вещи, как 'where io = liftIO' для функций, а вместо' liftIO' используется функция 'io', чтобы уменьшить типизацию. В идеале мы имели бы 'hPutStrLn :: MonadIO m => Handle -> String -> m()', но мы не можем ожидать, что функции из 'base' будут зависеть от классов, определенных в сторонних библиотеках (даже если эти библиотеки часть платформы haskell). – bheklilr

+1

Если у вас есть последовательность действий ввода-вывода, вы можете изменить 'do liftIO action1; liftIO action2' to 'liftIO $ do action1; action2', чтобы сэкономить некоторые лифты. – chi

ответ

3

Нельзя избежать liftIO, к сожалению, потому что стандартные действия IO не перегружены для работы ни в одном MonadIO. Но вы можете присоединиться к последовательности IO действий в рамках одного вызова liftIO:

intoFile :: String -> Cursor -> Action IO() 
intoFile ric c = do 
    outH <- liftIO $ do 
    openFile ric AppendMode 
    hPutStrLn outH "Some log" 
    loopIntoFile outH c 
    liftIO $ hClose outH 

Или, если вы собираетесь использовать те же самые IO операции повторно, вы можете ввести вспомогательные определения для них:

intoFile :: String -> Cursor -> Action IO() 
intoFile ric c = do 
    outH <- openLog ric AppendMode 
    log outH "Some log" 
    loopIntoFile outH c 
    closeLog outH 

openLog path mode = liftIO (openFile path mode) 
log handle message = liftIO (hPutStrLn handle message) 
closeLog handle = liftIO (hClose handle) 
0

Вы хотите провести еще 2 контекста - контекст IO и Action. Это относится к трансформаторам монады, потому что они позволяют вам справляться с накладными монадами и выбирать внутри блока do, в котором монада выбирает желаемое действие. Here is a great explanation, почему они нам нужны и как их использовать.

+0

Я бы посоветовал вам внимательно прочитать этот вопрос. – dfeuer

Смежные вопросы