2015-08-28 52 views
6

我想在Haskell中編寫一個共軛梯度解算器,並希望使用惰性列表來解耦停止規則以及迭代中信息的輸出。我的代碼基本上是這樣的:垃圾收集列表,同時在其上運行IO操作

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 

的想法是遍歷清單,輸出一些信息,但只保留最後一個迭代。但是,運行此代碼時,似乎並未收集前面的迭代。我的猜測是,這是連接到IO:如果我喜歡改寫

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

代碼不會出現問題,即一切,但最終迭代得到直接收集垃圾。

我怎樣才能達到相同的效果,同時能夠輸出關於迭代的一些信息?

回答

6

對,我覺得這個問題是在IOfmap:因爲IO行動是在嚴格的順序總是執行,該fmap僅適用從forM整個結果列表後last已建成。

相反,你可以可能使用Control.Monad.foldM,它比(未經測試)列表monadically褶皺:

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)