我想在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
问题不会发生,即除最终迭代之外的所有内容都会直接收集垃圾。
如何在输出有关迭代的一些信息的同时实现相同的效果?
答案 0 :(得分:6)
是的,我认为问题出在fmap
中的IO
:因为IO
操作始终按严格顺序执行,fmap
仅应用last
在之后<{1}}构建了整个结果列表。
相反,您可以使用forM
,它会在列表中单独折叠(未经测试):
Control.Monad.foldM