GHC 声称模块仅在不应作为引导模块时可用

GHC claims module only available as a boot module when it shouldn't be

我有这个依赖图(忽略对第三方模块的依赖):

Main:
    GSI.Util
    GSI.Value
    GSI.Result
    GSI.Eval
    GSI.ByteCode
    GSI.Thread
GSI.Main:
    GSI.Value
    GSI.ByteCode
GSI.Thread:
    GSI.Util
    GSI.RTS
    GSI.Value
    GSI.Result
    GSI.Eval
GSI.Eval:
    GSI.Util
    GSI.RTS
    GSI.Value
    GSI.Result
    ACE
GSI.Eval (.hs-boot):
    GSI.Value
ACE:
    GSI.RTS
    GSI.Value
    GSI.ByteCode
    GSI.Result
    {-# SOURCE #-} GSI.Eval
GSI.ByteCode:
    GSI.Util
    GSI.Value
    {-# SOURCE #-} GSI.Thread
GSI.ByteCode (.hs-boot):
    {-# SOURCE #-} GSI.Value
    {-# SOURCE #-} GSI.Thread
GSI.Result:
    GSI.Util
    GSI.RTS
    GSI.Value
GSI.Value:
    GSI.Util
    GSI.RTS
    {-# SOURCE #-} GSI.ByteCode

(我想进一步缩小该图,但老实说我不知道​​哪些部分是相关的。未列出的 .hs-boot 文件与我的代码没有依赖关系)。当我这样做时

ghc --make Main.hs

我收到这条消息:

[10 of 13] Compiling ACE              ( ACE.hs, ACE.o ) [GSI.ByteCode changed]
module GSI.Thread cannot be linked; it is only available as a boot module

到底是什么?我从 Main 导入 GSI.Thread 不是作为引导模块,那么 GHC 怎么能声称它只能作为引导模块使用呢? (而且,就此而言,为什么 GHC 不能检测到这种情况并自动包含非引导模块?)

实际问题是 ACE 和 GSI.Value 存在循环依赖关系:

ACE -> GSI.Value -> GSI.Thread -> GSI.Eval -> ACE

这是一个无法解决的问题,因为 ACE 在模板 Haskell 拼接中使用了来自 GSI.Value 的函数。这需要 GHC 动态加载 GSI.Value 才能编译 ACE;但这显然是不可能的。

解决方案是将 Thread 类型从 GSI.Thread 中移出,并移动到一个单独的模块中,以避免对 GSI.Eval 或 GSI.Value 的任何依赖。