Chr*_*isR 6 garbage-collection haskell 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
Run Code Online (Sandbox Code Playgroud)
我们的想法是迭代列表,输出一些信息,但只保留最后一次迭代.但是,在运行此代码时,它似乎不会垃圾收集前面的迭代.我的猜测是这与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
Run Code Online (Sandbox Code Playgroud)
问题不会发生,即除最终迭代之外的所有内容都会直接收集垃圾.
如何能够输出有关迭代的一些信息,我怎么能达到同样的效果?
对,我觉得这个问题是fmap在IO:由于IO操作是在严格的顺序总是执行中,fmap只有应用last 后,从整个结果列表中forM已建成.
相反,你可以使用Control.Monad.foldM,它在列表上单独折叠(未经测试):
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)
Run Code Online (Sandbox Code Playgroud)