获取Monad中的IO

Eri*_*ton 5 haskell binaryfiles redis

所以我的问题如下.我正在尝试为RDB文件(Redis生成的转储文件)实现流式解析器.我想实现一个类似于mapM_的函数,我可以说,在解析时打印出转储文件中表示的每个对象.但是,我似乎无法让它在恒定的空间中运行.我发现正在发生的事情是我在Get monad中构建一个大的IO()thunk,从Get monad返回然后执行IO.无论如何流式传输我的对象,因为它们被分析打印然后丢弃它们?我尝试过Enumerators and Conduits,但我没有看到任何真正的收获.这是我到目前为止:

loadObjs_ :: (Monad m) => (Maybe Integer -> BL8.ByteString -> RDBObj -> Get (m a)) -> Get (m a)
loadObjs_ f = do
             code <- lookAhead getWord8
             case code of
                0xfd -> do
                 skip 1
                 expire <- loadTime
                 getPairs_ f (Just expire)
               0xfc -> do
                 skip 1
                 expire <- loadTimeMs
                 getPairs_ f (Just expire)
               0xfe -> f Nothing "Switching Database" RDBNull
               0xff -> f Nothing "" RDBNull
               _ -> getPairs_ f Nothing

getPairs_ :: (Monad m) => (Maybe Integer -> BL8.ByteString -> RDBObj -> Get (m a)) -> Maybe Integer -> Get (m a)
getPairs_ f ex = do
                !t <- getWord8
                !key <- loadStringObj False
                !obj <- loadObj t
                !rest <- loadObjs_ f
                !out <- f ex key obj
                return (out >> rest)


(loadObj does the actual parsing of a single object but I believe that whatever I need to fix the streaming to operate in constant or near-constant memory is at a higher level in the iteration than loadObj)

getDBs_ :: (Monad m) => (Maybe Integer -> BL8.ByteString -> RDBObj -> Get (m a)) -> Get (m a)
getDBs_ f = do
           opc <- lookAhead getWord8
           if opc == opcodeSelectdb
              then do
                  skip 1
                  (isEncType,dbnum) <- loadLen
                  objs <- loadObjs_ f
                  rest <- getDBs_ f
                  return (objs >> rest)
              else f Nothing "EOF" RDBNull

processRDB_ :: (Monad m) => (Maybe Integer -> BL8.ByteString -> RDBObj -> Get (m a)) -> Get (m a)
processRDB_ f = do
                header <- getBytes 9
                dbs <- getDBs_ f
                eof <- getWord8
                return (dbs)

printRDBObj :: Maybe Integer -> BL8.ByteString -> RDBObj -> Get (IO ())
printRDBObj (Just exp) key obj = return $ (print ("Expires: " ++ show exp) >>
                                           print ("Key: " ++ (BL8.unpack key)) >> 
                                           print ("Obj: " ++ show obj))
printRDBObj Nothing key RDBNull = return $ (print $ BL8.unpack key)
printRDBObj Nothing key obj = return $ (print ("Key: " ++ (BL8.unpack key)) >> 
                                        print ("Obj: " ++ show obj))


main = do
       testf <- BL8.readFile "./dump.rdb"
       runGet (processRDB_ printRDBObj)  testf
Run Code Online (Sandbox Code Playgroud)

在此先感谢所有人.

最好的,Erik

编辑:这是我尝试将对象解析为惰性列表,然后将IO解析为惰性列表.

processRDB :: Get [RDBObj]

processRDB = do
                header <- getBytes 9
                dbs <- getDBs
                eof <- getWord8
                return (dbs)

main = do
       testf <- BL8.readFile "./dump.rdb"
       mapM_ (print . show) $ runGet processRDB testf
Run Code Online (Sandbox Code Playgroud)

Pau*_*son 2

如果我正确理解您的代码,您正在尝试将文件内容增量转换为 IO 操作,希望随后增量执行这些操作。

更好的方法是让解析器返回一个惰性对象列表,然后将其打印出来。