2015-08-28 20 views
6

Haskell'de bir konjugat degrade çözücü yazmak istiyorum ve durma kuralını ve yinelemeden bilgi çıktısını ayırmak için tembel listeleri kullanmak istiyorum. Çıktı bazı bilgiler,Bir IO eylemi yürütülürken bir liste toplama çöp kutusu

data CGState = CGState { cgx :: Image 
         , cgp :: Image 
         , cgr :: Image 
         , cgr2 :: Double 
         } 

cg :: Operator -> Image -> [CGState] 
cg = [...] 

runCG :: (CGState -> Bool) -> Operator -> Image -> IO Image 
runCG stoprule op rhs = do 
    let steps = takeWhile (not . stoprule) $ cg op rhs 
    fmap last $ forM (zip [(1::Int)..] steps) $ \(n, cgs) -> do 
     putStrLn $ show n ++ " " ++ show (sqrt $ cgr2 cgs) 
     return $ cgx cgs 

fikri listesi üzerinde yineleme yapmak, ancak yalnızca son iterate korumak: My kodu esas buna benzer. Ancak, bu kodu çalıştırırken, önceki yinelemeleri toplamak için çöp gözükmemektedir. Benim tahminim bu ES bağlı olduğundan: Ben sorun oluşmaz

runCG :: (CGState -> Bool) -> Operator -> Image -> IO Image 
runCG stoprule op rhs = do 
    let steps = takeWhile (not . stoprule) $ cg op rhs 
    return $ cgx $ last steps 

gibi kod, son yinelerler doğrudan toplanan çöp alır ama yani herşeyi yeniden eğer.

Yinelemelerle ilgili bazı bilgileri verirken aynı etkiyi nasıl elde edebilirim?

cevap

6

Doğru, sorun IO içinde fmap ile olduğunu düşünüyorum: IO eylemler hep sıraya göre yürütülür çünkü, fmap sadece inşa edilmiştirforM tamamını sonuç listesi sonra lastgeçerlidir.

runCG stoprule op rhs = do 
    let steps = takeWhile (not . stoprule) $ cg op rhs 
    foldM (\ _ (n, cgs) -> do 
     putStrLn $ show n ++ " " ++ show (sqrt $ cgr2 cgs) 
     return $ cgx cgs) 
    undefined -- initial value for fold is ignored as long as steps is nonempty 
    (zip [(1::Int)..] steps) 
:

yerine muhtemelen (denenmemiş) bir liste üzerinde monadik kıvrımları olan Control.Monad.foldM kullanabilirsiniz