2011-01-28 16 views
12

Data.Binary.Put monad'ını bir diğerine sarmaya çalışıyorum, daha sonra "kaç tane bayt yazacağı" veya "dosyadaki geçerli konum nedir" gibi sorular sorabilirim. Ama çok önemsiz sarar gibi:Data.Binary.Put monad'ı neden bir bellek sızıntısı oluşturur?

data Writer1M a = Writer1M { write :: P.PutM a } 
or 
data Writer2M a = Writer2M { write :: (a, P.Put) } 

büyük uzay sızıntısına yol ve program genellikle (4GB RAM yukarı aldıktan sonra) çöküyor. İşte ben bugüne kadar denedim budur:

-- This works well and consumes almost no memory. 

type Writer = P.Put 

writer :: P.Put -> Writer 
writer put = put 

writeToFile :: String -> Writer -> IO() 
writeToFile path writer = BL.writeFile path (P.runPut writer) 

-- This one will cause memory leak. 

data Writer1M a = Writer1M { write :: P.PutM a } 

instance Monad Writer1M where 
    return a = Writer1M $ return a 
    ma >>= f = Writer1M $ (write ma) >>= \a -> write $ f a 

type WriterM = Writer1M 
type Writer = WriterM() 

writer :: P.Put -> Writer 
writer put = Writer1M $ put 

writeToFile :: String -> Writer -> IO() 
writeToFile path writer = BL.writeFile path (P.runPut $ write writer) 
-- This one will crash as well with exactly the 
-- same memory foot print as Writer1M 

data Writer2M a = Writer2M { write :: (a, P.Put) } 

instance Monad Writer2M where 
    return a = Writer2M $ (a, return()) 
    ma >>= f = Writer2M $ (b, p >> p') 
         where (a,p) = write ma 
           (b,p') = write $ f a 

type WriterM = Writer2M 
type Writer = WriterM() 

writer :: P.Put -> Writer 
writer put = Writer2M $ ((), put) 

writeToFile :: String -> Writer -> IO() 
writeToFile path writer = BL.writeFile path (P.runPut $ snd $ write writer) 

Ben Haskell yeniyim ve bu benim için hiçbir sense yapar, ama sarıcı monads böylece orada tahmin ediyorum çok önemsiz görünüyor eksik olduğum belli bir şey.

Baktığınız için teşekkür ederiz.

GÜNCELLEME

: http://hpaste.org/43400/why_wrapping_the_databinaryp

Update2: Burada sorunu gösteren bir örnek kod da bu soruya here bir ikinci bölümü vardır.

+1

Hangi compiler bayraklarını kullanıyorsunuz? –

+0

-O2 ile denediğimi sorduktan sonra (daha önce hiç kullanmadım) ancak bellek ayağı baskısı değişmedi. –

+0

Önemsiz bir test programı gönderebilir misiniz, böylece burada başkaları kendi başlarına inşa etmek zorunda kalmazlar mı? –

cevap

4

, ben sorun ikili en (>> =) uygulamaya kullanımı gibi görünüyor bulundu (>>).

m >> k = Writer1M $ write m >>= const (write k) 

(>>), binary's source baktığımızda birinci monadın sonucunu atmak gibi görünüyor: Bu versiyon hala bellek sızdırıyor Oysa

m >> k = Writer1M $ write m >> write k 

: Writer1M monad uygulanmasına aşağıdaki ilave sorunu çözer açıkça. Yine de bunun tam olarak nasıl sızıntıyı önlediğinden emin değil. En iyi teorim, GHC'nin başka bir şekilde DoubleS nesnesine dayanması ve "a" referans sızıntısı olmamasıdır, çünkü asla bakılmaz.

2

Eğer sıkı monad daha yapmaya çalıştı mı? Örneğin. datatyp kesinlikle yapıcıları yapmaya çalışın/bunları bir yeni tiple değiştirin.

Ben tam sorun burada ne olduğunu bilmiyorum, ama bu sızıntı zamanki kaynağıdır.

PS: Ve mesela gereksiz lambdas kaldırmaya çalışırsanız: biraz etrafı alay sonra

ma >>= f = Writer1M $ (write ma) >=> write . f 
+0

Verilerden yeni bir yazıya geçmek, #haskell'deki iyi kişilerin de önerdiği gibi, ne yazık ki bunu değiştirerek ve lambdayı önerdiğiniz gibi çıkartmak bellek ayağı baskısını değiştirmedi. Ancak öneri için teşekkürler. –

+0

Profil oluşturmayı denediniz mi? – fuz

+0

Evet, işte sonuç: http://i.imgur.com/4Q2E3.png, sarmalayıcılardan birini kullandığımda sarı alan görünüyor. –