그래서 내 문제는 다음과 같습니다. RDB 파일 (Redis가 생성하는 덤프 파일) 용 스트리밍 파서를 구현하려고합니다. mapM_와 비슷한 기능을 구현하고 싶습니다. 구문 분석 할 때마다 덤프 파일에 표시된 각 객체를 출력 할 수 있습니다. 그러나, 나는 그것이 일정한 공간에서 작동하도록 할 수 없습니다. 내가 무슨 일이 일어나고 있다는 것을 알게되면, Get 모나드 내부에 큰 IO() 썽크를 만들고, Get 모나드에서 돌아온 다음 IO를 실행하고있다. 인쇄물을 파싱 한 다음 폐기하기 위해 객체를 스트리밍 할 여지가 있습니까? 나는 열거 자 (Enumerators)와 도관 (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
미리 감사드립니다.
최저
, 에릭편집 : 여기에 게으른리스트를 다음 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
http://hackage.haskell.org/package/binary-strict를 사용해 보셨습니까? –
나는 binary-strict를 시도하지는 않았지만, 시리얼을 엄격하게 사용하려고 시도하지는 않았다. –
당신은 그것을 더 엄격하게 만들고 싶지 않습니다, 당신은 그것을 게으르게 만들고 싶습니다. 뭔가 어딘가 너무 엄격합니다. 그러나 관련 패키지를 잘 이해할 수는 없습니다. –