我有一个过程,(a)做一些IO,(b)构造一个查找表,(c)返回一个使用查找表的IO动作。但是当使用-O
进行编译时,GHC(版本6.12.1)会内联构建查找表,以便在每次调用IO操作时对其进行重新评估。
示例:
module Main where
import Data.Array
import Data.IORef
import Control.Monad
makeAction getX getY sumRef = do
x <- getX
let a = listArray (0, 1000) [x ..]
return $ do
y <- getY
modifyIORef sumRef (\sum -> sum + a ! y)
main = do
sumRef <- newIORef 0
action <- makeAction getX getY sumRef
replicateM_ 100000 action
n <- readIORef sumRef
putStrLn (show n)
where
getX = return (1 :: Int)
getY = return 0
这个问题是否足以让人有一个标准的GHC万无一失的解决方法 - 或者你如何调整程序以便不会重复分配a
?
答案 0 :(得分:4)
最简单的解决方法是使用严格注释强制进行评估。
{-# LANGUAGE BangPatterns #-}
然后使用a
(“bang”)简单地强制!
强制分配。
let !a = listArray (0, 1000) [x ..]
或者,如果您在IO
monad中工作,严格注释可能并不总是有帮助。要在运行某些IO
操作之前强制评估表达式,可以使用evaluate
。例如:
let a = listArray (0, 1000) [x ..]
evaluate a
答案 1 :(得分:2)
在构造要返回的monadic值时尝试强制a
:
makeAction getX getY sumRef = do
x <- getX
let a = listArray (0, 1000) [x ..]
return $ a `seq` do
y <- getY
modifyIORef sumRef (\sum -> sum + a ! y)