2011-02-06 5 views
5

(a)IOをいくつか行い、(b)ルックアップテーブルを構築し、(c)ルックアップテーブルを使用するIOアクションを返します。しかし、-Oでコンパイルすると、GHC(バージョン6.12.1)は構造をルックアップテーブルにインライン化するので、IOアクションの呼び出しごとに再評価されます。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

プラグマ '{ - #NOINLINE# - }'を試しましたか? – fuz

+0

@FUZxxlはい、 '{ - #NOINLINE a# - }'はローカルの 'a'でそれをしません。 – antonakos

+0

ルックアップテーブルを必要とし、繰り返しアクション間で共有したい場合は、必ず@ makeAction @関数から作成する必要があります。 makeActionはインライン展開に関係なく毎回配列を作成するようです。おそらく、あなたはmakeAction関数から引き上げられたIOArrayを使うべきです。 –

答えて

4

最も簡単な回避策は正格性注釈を使用して評価を強制することです。

{-# LANGUAGE BangPatterns #-} 

単に!( "バン")を用いて厳密aを行うことで、割り当てを強制します。あなたはIOモナドで作業している場合

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

あるいは、厳密注釈は常に助けないかもしれません。 IOアクションが実行される前に式の評価を強制するには、evaluateを使用します。例:

let a = listArray (0, 1000) [x ..] 
    evaluate a 
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) 
関連する問題