在IO动作中重复评估纯表达

时间:2011-02-06 11:35:11

标签: haskell io closures ghc inlining

我有一个过程,(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

2 个答案:

答案 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)