Repeated evaluation of pure expression in IO action

本小妞迷上赌 提交于 2019-12-10 13:53:49

问题


I have a procedure that (a) does some IO, (b) constructs a lookup table, and (c) returns an IO action that uses the lookup table. But when compiled with -O, GHC (version 6.12.1) inlines the construction the lookup table, so that it is reevaluated for every call of the IO action.

Example:

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

Is this issue well-known enough to have a standard GHC-foolproof workaround - or how would you adjust the program so that a isn't repeatedly being allocated?


回答1:


The easiest workaround is to force evaluation by using strictness annotations.

{-# LANGUAGE BangPatterns #-}

Then force allocation by simply making a strict using a ! ("bang").

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

Alternatively, if you are working in the IO monad, strictness annotations may not always help. To force evaluation of an expression before some IO action is run, you can use evaluate. For example:

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



回答2:


Try forcing a when constructing the monadic value to return:

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)


来源:https://stackoverflow.com/questions/4913020/repeated-evaluation-of-pure-expression-in-io-action

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!