2011-06-27 12 views
3

GHC APIでは、起動前にいくつかの初期化が必要です。具体的には、parseStaticFlagsは一度だけ呼び出すことができます。HaskellのunsafePerformIOによるグローバル変数

私はいくつかのGHC APIメソッドを実行するためにrunGhc :: MaybeFilePath :: Ghc a -> IO aを何度も呼び出すことができる関数を持っています。ただし、その初期化の一部は、関数が呼び出されたときに初めて発生する必要があります。

私はrunGhcを呼び出すモナドアクションで私たちは、しかし

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

を持つことができるように

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

のようなグローバル変数ものを作成することが可能であることをYiソースから覚えているようです私はそれがどのように行われたかを正確に思い出すことはできません。このコードはGhcMonadをラップするモナドの関数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

ああ、私は 'MVar'ではなく' IORef'を使っていたはずです。 – vivian

+1

いいえ、MVarが良いです。実際にはMVarは並行処理でも機能するため、より優れています。 – augustss

+0

'MVar'を使用したときに私のプログラムがハングしていました。 – vivian

2

インラインをオフにする必要があります。 他の重要なこと:タイプはモノモルフ(=タイプ変数なし)でなければなりません。実際のタイプごとにunsafePerformIOを評価するかもしれません。

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