【问题标题】:Global variables via unsafePerformIO in HaskellHaskell中通过unsafePerformIO的全局变量
【发布时间】:2011-09-23 05:46:33
【问题描述】:

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)

但是,我不记得它是如何完成的。这段代码在包裹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)

【问题讨论】:

    标签: haskell ghc ghc-api


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      this answer。它展示了如何使用一个全局计数器,每次你看它时都会“打勾”。您不需要计数器,但您只需将 True 放入其中,而不是 +1

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

      【讨论】:

      • 啊,我应该用IORef而不是MVar
      • 不,MVar 很好。 MVar 实际上更好,因为它甚至可以在并发的情况下工作。
      • 当我使用MVars时我的程序挂了。
      • 您的readMVar 应该是takeMVar,否则putMVar 将被阻止。
      • 但请注意,如果您切换到 takeMVar,即使它已经初始化,您也需要 putMVar 来匹配它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-27
      • 2013-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-23
      • 1970-01-01
      相关资源
      最近更新 更多