Haskell 中通过 unsafePerformIO 的全局变量
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)
The GHC API requires that some initialisation occurs before invocation. Specifically, parseStaticFlags
can only be called once.
I have functions that can call runGhc :: MaybeFilePath :: Ghc a -> IO a
multiple times to run some GHC API methods. However, some of that initialisation should only occur the first time that function is called.
I seem to remember from Yi
source that it is possible to create a global variable something like
ghcInitialised :: MVar (Bool,[String])
ghcInitialised = unsafePerformIO $ newMVar (False,[])
so that in the monadic action that calls runGhc
we can have
(init,flags) <- readMVar ghcInitialised
when (not init) $ do
...
(_,_,staticFlagWarnings) <- parseStaticFlags ...
...
putMVar ghcInitialised (True,staticFlagWarnings)
However, I can not recall exactly how it is done. This code is in the runMonad
function for the monad that wraps a GhcMonad
. I am well aware that using unsafePerformIO
is not pure or functional, but (at the time) this was the best way of achieving a practical result.
[Edit: the working solution:
{-# NOINLINE ghcInitialised #-}
ghcInitialised :: MVar (Bool,[String])
ghcInitialised = unsafePerformIO $ newMVar (False,[])
so that in the monadic action that calls runGhc
we can have
(init,flags) <- takeMVar ghcInitialised
when (not init) $ do
...
(_,_,staticFlagWarnings) <- parseStaticFlags ...
...
putMVar ghcInitialised (True,staticFlagWarnings)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您需要关闭内联。
另一件重要的事情:类型必须是单态的(=没有类型变量),否则你可能会为每个实际类型评估 unsafePerformIO 。
You need to turn inlining off.
The other important thing: The type has to be monomorph (= no type variables), otherwise you might evaluate unsafePerformIO for each actual type.
请参阅此答案。它展示了如何使用每次查看时都会“滴答作响”的全局计数器。您不需要计数器,但只需将
True
放入其中即可,而不是+1
。或者,更好的是,您将初始化代码放入
unsafePerformIO
中(当然由if
保护)。See this answer. It shows how to use a global counter that 'ticks' everytime you look at it. You don't need a counter, but instead of
+1
, you just putTrue
into it.Or, even better, you put the initialisation code into the
unsafePerformIO
, (guarded by anif
of course).