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

ant*_*kos 5 io closures haskell inlining ghc

我有一个过程,(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
Run Code Online (Sandbox Code Playgroud)

这个问题是众所周知的,有足够的标准GHC万无一失的解决方法 - 或者你如何调整程序,以免a重复分配?

nom*_*olo 4

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

{-# LANGUAGE BangPatterns #-}
Run Code Online (Sandbox Code Playgroud)

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

    let !a = listArray (0, 1000) [x ..]
Run Code Online (Sandbox Code Playgroud)

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

    let a = listArray (0, 1000) [x ..]
    evaluate a
Run Code Online (Sandbox Code Playgroud)