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) 
관련 문제