垃圾收集列表,同时对其执行IO操作

时间:2015-08-28 08:18:53

标签: haskell garbage-collection lazy-evaluation

我想在Haskell中编写一个共轭梯度求解器,并希望使用惰性列表来解除停止规则和迭代中的信息输出。我的代码基本上是这样的:

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

问题不会发生,即除最终迭代之外的所有内容都会直接收集垃圾。

如何在输出有关迭代的一些信息的同时实现相同的效果?

1 个答案:

答案 0 :(得分:6)

是的,我认为问题出在fmap中的IO:因为IO操作始终按严格顺序执行,fmap仅应用last 之后<{1}}构建了整个结果列表。

相反,您可以使用forM,它会在列表中单独折叠(未经测试):

Control.Monad.foldM