通过Haskell中的unsafePerformIO实现全局变量

通过Haskell中的unsafePerformIO实现全局变量,haskell,ghc,ghc-api,Haskell,Ghc,Ghc Api,GHC API要求在调用之前进行一些初始化。具体来说,parseStaticFlags只能调用一次 我有一些函数可以多次调用runGhc::MaybeFilePath::Ghc a->IO a来运行一些Ghc-API方法。但是,有些初始化应该只在第一次调用该函数时发生 我似乎记得从Yisource可以创建一个全局变量,比如 ghcInitialised :: MVar (Bool,[String]) ghcInitialised = unsafePerformIO $ newMVar (Fals

GHC API要求在调用之前进行一些初始化。具体来说,
parseStaticFlags
只能调用一次

我有一些函数可以多次调用
runGhc::MaybeFilePath::Ghc a->IO a
来运行一些Ghc-API方法。但是,有些初始化应该只在第一次调用该函数时发生

我似乎记得从
Yi
source可以创建一个全局变量,比如

ghcInitialised :: MVar (Bool,[String])
ghcInitialised = unsafePerformIO $ newMVar (False,[])
因此,在调用
runGhc
的一元操作中,我们可以

(init,flags) <- readMVar ghcInitialised
when (not init) $ do
   ...
   (_,_,staticFlagWarnings) <- parseStaticFlags ...
   ...
   putMVar ghcInitialised (True,staticFlagWarnings)
(init,flags) <- takeMVar ghcInitialised
when (not init) $ do
   ...
   (_,_,staticFlagWarnings) <- parseStaticFlags ...
   ...
   putMVar ghcInitialised (True,staticFlagWarnings)
因此,在调用
runGhc
的一元操作中,我们可以

(init,flags) <- readMVar ghcInitialised
when (not init) $ do
   ...
   (_,_,staticFlagWarnings) <- parseStaticFlags ...
   ...
   putMVar ghcInitialised (True,staticFlagWarnings)
(init,flags) <- takeMVar ghcInitialised
when (not init) $ do
   ...
   (_,_,staticFlagWarnings) <- parseStaticFlags ...
   ...
   putMVar ghcInitialised (True,staticFlagWarnings)
(初始化,标志)请参阅。它展示了如何使用一个全局计数器,每次你看到它时它都会“滴答”一声。您不需要计数器,但只需将
True
放入计数器,而不是
+1


或者,更好的是,您将初始化代码放入
unsafePerformIO
,(当然由
if
保护)。

您需要关闭内联。 另一件重要的事情:类型必须是monomorph(=没有类型变量),否则您可能会为每个实际类型计算unsafePerformIO

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

啊,我应该使用
IORef
而不是
MVar
。不,MVar很好。MVar实际上更好,因为它甚至可以与并发一起工作。当我使用
MVar
s时,我的程序挂起了。你的
readMVar
应该是
takeMVar
,否则
putMVar
会被阻塞。但是要小心,如果您切换到
takeMVar
,您将需要
putMVar
来匹配它,即使它已经初始化。