垃圾收集列表,同时 运行 对其进行 IO 操作
Garbage collecting a list while running an IO action over it
我想在 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
问题没有发生,即除了最终迭代之外的所有内容都直接被垃圾收集。
如何在能够输出有关迭代的一些信息的同时达到相同的效果?
是的,我认为问题出在 IO
中的 fmap
:因为 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)
我想在 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
问题没有发生,即除了最终迭代之外的所有内容都直接被垃圾收集。
如何在能够输出有关迭代的一些信息的同时达到相同的效果?
是的,我认为问题出在 IO
中的 fmap
:因为 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)