2012-09-26 26 views
11

varsayalım, ben öğelerin büyük liste alıyorum:tembel versiyonu

as <- getLargeList 
bs <- mapM fn as 

mapM sahiptir: Artık

as <- getLargeList 

, ben fn :: a -> IO bas üzerine uygulamak çalışıyorum mapM :: Monad m => (a -> m b) -> [a] -> m [b] yazın ve tür eşleme açısından ihtiyacım olan şey budur. Ancak sonucu döndürene kadar tüm zinciri hafızada oluşturur. Ben tembel çalışacak mapM, ben hala kuyruk inşa ederken bs başkanı kullanabilir, böylece analog arıyorum.

+1

Belki bu yardımcı olacaktır. http://stackoverflow.com/questions/3270255/is-haskells-mapm-not-lazy –

+0

Anton, Bu konuyu okudum, ama cevabı bulamadım: tembel hesaplamalar için mapM bir alternatif var. –

+0

@DmitryBespalov Aynı tür imzayla değil. Monad'ın daha sonraya kadar etkileri ertelemek için bir soyutlaması yoktur - bu da 'mapM'nin daha tembel olması için yapmanız gereken şey. – Carl

cevap

18

bu konuda unsafeInterleaveIO veya herhangi tembel IO kullanmayın. Bu, yinelemelerin, tahmin edilemeyen kaynak yönetimini sağlayan tembel IO'dan kaçınmak için oluşturulduğu problemdir. Hile asla listesini oluşturmak ve bunu kullanarak bitene kadar yineleme kullanarak sürekli akışı. Bunu göstermek için kendi kütüphanemden, pipes'dan örnekler kullanacağım.

Öncelikle tanımlayın:

import Control.Monad 
import Control.Monad.Trans 
import Control.Pipe 

-- Demand only 'n' elements 
take' :: (Monad m) => Int -> Pipe a a m() 
take' n = replicateM_ n $ do 
    a <- await 
    yield a 

-- Print all incoming elements 
printer :: (Show a) => Consumer a IO r 
printer = forever $ do 
    a <- await 
    lift $ print a 

Şimdi bizim kullanıcıya ortalama olalım ve onlar bizim için gerçekten büyük liste üretmek talep: Artık

prompt100 :: Producer Int IO() 
prompt100 = replicateM_ 1000 $ do 
    lift $ putStrLn "Enter an integer: " 
    n <- lift readLn 
    yield n 

, hadi çalışmasına izin:

>>> runPipe $ printer <+< take' 1 <+< prompt100 
Enter an integer: 
3<Enter> 
3 

Sadece bir tam sayı ister, çünkü yalnızca bir tam sayı isteriz!

yourProducer :: Producer b IO() 
yourProducer = do 
    xs <- lift getLargeList 
    mapM_ yield xs 

... sonra çalıştırın: Eğer getLargeList dan çıkışı ile prompt100 değiştirmek istiyorsanız

, sadece yazma

>>> runPipe $ printer <+< take' 1 <+< yourProducer 

Bu lazily inşa listesini akışı ve asla güvenli olmayan tüm IO hacks kullanmadan, bellekte liste. Sadece böyle fazla örnek için take'

geçmek değerini değiştirmek, sen talep kaç unsurlar değiştirmek için Control.Pipe.Tutorial de pipes tutorial okuyun.

tembel IO sorunlara neden niçin hakkında daha fazla bilgi için, here bulabilirsiniz konuyla ilgili Oleg'in orijinal slaytlar okuyun.Tembel IO kullanarak sorunları açıklamak için harika bir iş çıkarır. Tembel IO kullanmaya zorlandığınız her zaman, gerçekten istediğiniz şey yinelenen bir kütüphanedir.

+5

+100 boru kütüphanesi için –

+2

Gabriel, cevap için teşekkürler! Ve gerçekten kullanışlı bir kütüphane, teşekkürler! –

+0

@DmitryBespalov Rica ederim! Yardım etmek için her zaman mutluyum. –

6

IO monad'ın etkileri ertelemek için bir mekanizması vardır. Buna unsafeInterleaveIO denir. İstenilen efekti elde etmek için kullanabilirsiniz: Bu, tembel IO'nun nasıl uygulandığıdır. Etkilerin gerçekte uygulanacağı düzenin öngörülmesi zor olduğu ve sonuç listesindeki unsurların değerlendirildiği sıraya göre belirleneceği doğru değildir. Bu nedenle, f'daki herhangi bir IO etkisinin, duyarsız olmaları gerektiği için iyi huylu olması önemlidir. Yeterince iyi huylu bir etkiye iyi bir örnek, salt okunur bir dosyadan okumaktır.

+1

Benim açımdan, Haskell System.IO.Unsafe kullanarak bir kesmek gibi bir şey. "Güvenli olmayan" davranışı nedeniyle kullanmaktan kaçınmayı tercih ediyorum. Ancak cevabınızı takdir ediyorum. –