2011-06-15 15 views
10

Sadece Iteratees hakkında biraz bilgi edinmek, Data.Iteratee ve Data.Attoparsec.Iteratee kullanarak yaptığım basit bir ayrıştırıcıyı yeniden oluşturmak istedim. Yine de çok şaşırdım. Aşağıda bir dosyadan tek satırını ayrıştırabilen basit bir örneğim var. Ayrıştırıcım her seferinde bir satır okuyor, bu yüzden tamamlanana kadar yinelemeye doğru bir besleme çizgisine ihtiyacım var. Tüm bunları okuduğumu okudum, ama yinelemede/sayım yapanlarda çok fazla malzeme oldukça ilerlemiş.Attoparsec Iteratee

-- There are more imports above. 
import Data.Attoparsec.Iteratee 
import Data.Iteratee (joinI, run) 
import Data.Iteratee.IO (defaultBufSize, enumFile) 

line :: Parser ByteString -- left the implementation out (it doesn't check for 
          new line) 

iter = parserToIteratee line 

main = do 
    p <- liftM head getArgs 
    i <- enumFile defaultBufSize p $ iter 
    i' <- run i 
    print i' 

Bu örnek ayrıştırmak ve birden fazla satır içeren bir dosyadan bir satır yazdırılır: Bu konularda kod parçasıdır. Özgün komut dosyası, çözümleyiciyi bir ByteStrings listesi üzerinde eşleştirdi. Ben de aynı şeyi burada yapmak isterim. Iteratee'de enumLines buldum, ama hayatımın nasıl kullanılacağını anlayamıyorum. Belki amacını yanlış anladım?

cevap

15

Ayrıştırıcınız her seferinde bir çizgide çalıştığından, attoparsec-iteratee'yi kullanmanıza bile gerek yoktur. Bu bir dere dönüştürücü sadece iteratee terimdir "enumeratee" dir anlamanın

import Data.Iteratee as I 
import Data.Iteratee.Char 
import Data.Attoparsec as A 

parser :: Parser ParseOutput 
type POut = Either String ParseOutput 

processLines :: Iteratee ByteString IO [POut] 
processLines = joinI $ (enumLinesBS ><> I.mapStream (A.parseOnly parser)) stream2list 

anahtarı: Ben bu kadar yazardı. Bir akış türünün bir akış işlemcisini (iteratee) alır ve başka bir akışla çalışacak şekilde dönüştürür. Hem enumLinesBS hem de mapStream numaralandır. Nihai iteratee (stream2list) olduğunda

i1 :: Iteratee [ByteString] IO (Iteratee [POut] IO [POut] 
i1 = mapStream (A.parseOnly parser) stream2list 

iç içe iteratees sadece bu [POut] bir akışa [ByteString] akışı dönüştürür anlamına ve:

mapStream yeterlidir, birden fazla satır üzerinde ayrıştırıcı haritasını çıkarmak için çalıştır, bu akışı [POut] olarak döndürür. Şimdi sadece enumLinesBS yaptığı iştir [ByteString] o akışı oluşturmak için lines arasında iteratee eşdeğer gerekir:

i2 :: Iteratee ByteString IO (Iteratee [ByteString] IO (Iteratee [POut] m [POut]))) 
i2 = enumLinesBS $ mapStream f stream2list 

Ama bu fonksiyon çünkü bütün yuvalama kullanımına biraz yavaş olduğunu. Gerçekten istediğimiz şey, akışı dönüştürücüler arasında doğrudan çıktıya dönüştürmenin bir yoludur ve sonunda her şeyi tek bir yinelemeye basitleştirir. Ben inlined e1 ile, yukarıda yazdım nasıl eşdeğerdir

e1 :: Iteratee [POut] IO a -> Iteratee ByteString IO (Iteratee [POut] IO a) 
e1 = enumLinesBS ><> mapStream (A.parseOnly parser) 

i' :: Iteratee ByteString IO [POut] 
i' = joinI $ e1 stream2list 

: Biz joinI, (><>) ve (><>) kullanmak Bunu yapmak için.

Yine de hala kalan önemli öğeler var. Bu işlev, ayrıştırma sonuçlarını bir listede basitçe döndürür. Genellikle, sonuçları bir katla birleştirmek gibi başka bir şey yapmak istersiniz. Tüketiciler oluşturmak için genellikle yararlıdır. Bunları yazdırmak istiyorsanız sadece başarılı ayrıştırır yazdırır

consumeParse :: Iteratee [POut] IO() 
consumeParse = I.mapM_ (either (\e -> return()) print) 

processLines2 :: Iteratee ByteString IO() 
processLines2 = joinI $ (enumLinesBS ><> I.mapStream (A.parseOnly parser)) consumeParse 

Bu kullanabilmesi Bu noktada akımın her eleman, bir ayrıştırma sonucudur. Hataları STDERR'e kolayca rapor edebilir veya başka şekillerde de işleyebilirsiniz.

+0

İnanılmaz cevap, iki kez daha kazanabilseydim! Bu tüketicinin nasıl yazılacağına dair bir örnek isteyebilir miyim? Tek yapmak istediğim, basit bir örnek ise başarılı ayrıştırma sonuçlarını yazdırmak olduğunu varsayalım. –

+0

@shintoist: Bunu şimdi ekledim. –

+0

Mükemmel!Teşekkür ederim! –

İlgili konular