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)