Haskell中通过unsafePerformIO的全局变量

时间:2011-06-27 04:52:10

标签: haskell ghc ghc-api

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

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

我似乎记得Yi来源,可以创建类似

的全局变量
ghcInitialised :: MVar (Bool,[String])
ghcInitialised = unsafePerformIO $ newMVar (False,[])

以便在调用runGhc的monadic动作中我们可以拥有

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

但是,我不记得究竟是怎么做到的。此代码位于包含runMonad的monad的GhcMonad函数中。我很清楚使用unsafePerformIO不是纯粹的或功能性的,但(当时)这是实现实际结果的最佳方式。

[编辑:工作解决方案:

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

以便在调用runGhc的monadic动作中我们可以拥有

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

2 个答案:

答案 0 :(得分:2)

您需要关闭内联。 另一个重要的事情:类型必须是单形(=无类型变量),否则您可能会为每个实际类型评估unsafePerformIO。

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

答案 1 :(得分:1)

this answer。它展示了如何使用每次看到它时“滴答”的全局计数器。您不需要计数器,而是将+1放入其中,而不是True

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