5

我有一个过程,(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不会重复分配?

4

2 回答 2

4

最简单的解决方法是通过使用严格性注释来强制评估。

{-# LANGUAGE BangPatterns #-}

a然后通过简单地使用!(“bang”)进行严格分配来强制分配。

    let !a = listArray (0, 1000) [x ..]

或者,如果您在IOmonad 中工作,严格性注释可能并不总是有帮助。IO要在运行某些操作之前强制评估表达式,您可以使用evaluate. 例如:

    let a = listArray (0, 1000) [x ..]
    evaluate a
于 2011-02-06T13:23:45.973 回答
2

在构造一元值时尝试强制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)
于 2011-02-06T13:23:36.373 回答