2012-03-13 8 views
5

Więc mój problem jest następujący. Próbuję zaimplementować analizator składni strumieniowej dla plików RDB (pliki zrzutu tworzone przez Redis). Chcę zaimplementować funkcję podobną do mapM_, dzięki której mogę, na przykład, wypisać każdy obiekt reprezentowany w pliku zrzutu podczas jego analizy. Jednak nie mogę sprawić, by działał w stałej przestrzeni. Uważam, że to, co się dzieje, polega na tym, że buduję duży ruch wewnątrz IO() wewnątrz monady Get, wracając z monady Get, a następnie wykonując IO. Czy mimo to można przesyłać strumieniowo moje obiekty podczas ich drukowania, a następnie je odrzucić? Próbowałem już Enumeratory and Conduits, ale nie widziałem żadnych prawdziwych korzyści. Oto, co mam do tej pory:IO wewnątrz Get Monad

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 

Dziękuję z góry.

Best, Erik

EDIT: Oto moja próba analizowania obiektów do listy leniwej a następnie IO nad listą leniwe.

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 
+0

Czy próbowałeś http://hackage.haskell.org/package/binary-strict? –

+0

Nie próbowałem binarnie ścisłej, ale próbowałem ścisłe pobieranie zbóż bezskutecznie. –

+0

Nie chcesz, aby było bardziej rygorystyczne, chcesz sprawić, by było leniwiej. Coś gdzieś jest zbyt surowe. Ale nie znam wystarczająco dobrze odpowiednich pakietów. –

Odpowiedz

2

Gdybym poprawnie zrozumieć swój kod, który próbujesz konwertować zawartość pliku do działań IO stopniowo, w nadziei, że to wykonanie tych czynności stopniowo.

Lepszym rozwiązaniem byłoby mieć swoją parser powrócić leniwe listę obiektów, które następnie wydrukuj.

+1

Ach tak, próbowałem tego również. Mam wersję kodu, który analizuje RDB na listę obiektów, na których ja nazywam 'mapM_. (pokaż, pokaż) 'Niestety widzę ten sam szczyt sterty na początku mojej egzekucji, który stopniowo zanika, gdy przechodzi iteracje i zbiera śmieci: –

+0

Dodałem edycję pokazującą, co mam na myśli powyżej. –