2011-06-27 17 views
3

GHC API要求在調用之前進行一些初始化。具體而言,parseStaticFlags只能被調用一次。通過Haskell中的unsafePerformIO創建全局變量

我有多個函數可以調用runGhc :: MaybeFilePath :: Ghc a -> IO a多次運行一些GHC API方法。但是,一些初始化應該只在該函數第一次被調用時發生。

我似乎從Yi源,它可以創建一個全局變量類似

ghcInitialised :: MVar (Bool,[String]) 
ghcInitialised = unsafePerformIO $ newMVar (False,[]) 

要記住,這樣在調用runGhc的單子行動,我們纔能有

(init,flags) <- readMVar ghcInitialised 
when (not init) $ do 
    ... 
    (_,_,staticFlagWarnings) <- parseStaticFlags ... 
    ... 
    putMVar ghcInitialised (True,staticFlagWarnings) 

然而,我不記得它是如何完成的。此代碼位於包裝GhcMonad的monad的runMonad函數中。我很清楚,使用unsafePerformIO不是純粹的或功能性的,但(當時)這是實現實際結果的最佳方式。

[編輯:工作的解決方案:

{-# NOINLINE ghcInitialised #-} 
ghcInitialised :: MVar (Bool,[String]) 
ghcInitialised = unsafePerformIO $ newMVar (False,[]) 

,這樣在調用runGhc的單子行動,我們纔能有

(init,flags) <- takeMVar ghcInitialised 
when (not init) $ do 
    ... 
    (_,_,staticFlagWarnings) <- parseStaticFlags ... 
    ... 
    putMVar ghcInitialised (True,staticFlagWarnings) 

回答

1

this answer。它展示瞭如何使用一個全局計數器,每次你看它時都會'勾號'。你不需要一個計數器,但不是+1,你只需把True加入它。

或者,甚至更好的是,您將初始化代碼放入unsafePerformIO(當然是由if來保護)。

+0

啊,我應該使用'IORef'而不是'MVar'。 – vivian

+1

不,MVar很好。事實上MVar更好,因爲即使在併發的情況下它也能工作。 – augustss

+0

我使用'MVar'時,程序掛起。 – vivian

2

您需要關閉內聯。 另一個重要的事情是:類型必須是單形態(=沒有類型變量),否則你可能會評估每個實際類型的unsafePerformIO。

{-# NOINLINE ghcInitialised #-} 
ghcInitialised :: MVar (Bool,[String]) 
ghcInitialised = unsafePerformIO $ newMVar (False,[])