3

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

我有可以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)

但是,我不记得它是如何完成的。此代码位于runMonad包装 a 的 monad 的函数中GhcMonad。我很清楚使用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)
4

2 回答 2

2

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

{-# NOINLINE ghcInitialised #-}
ghcInitialised :: MVar (Bool,[String])
ghcInitialised = unsafePerformIO $ newMVar (False,[])
于 2011-06-28T13:48:00.480 回答
1

看到这个答案。它展示了如何使用一个全局计数器,每次你看它时都会“打勾”。您不需要计数器,但+1您只需放入True其中即可。

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

于 2011-06-27T08:40:54.187 回答