为什么 GHCi 理解 GHC 不理解的导入?

Why does GHCi understand imports that GHC doesn't?

我是 Haskell 的新手,我认为我在某个地方存在根本性的误解。当我在 GHCi 中(使用 ghci 命令)时,我可以输入 import System.Random,它可以工作。然后我可以生成随机数。

接下来,我创建了一个名为 test.hs 的文件,其中仅包含一行:import System.Random。然后我调用命令 ghc test.hs 并收到以下错误消息:

test.hs:1:1: error:
    Could not find module ‘System.Random’
    There are files missing in the ‘random-1.1’ package,
    try running 'ghc-pkg check'.
    Use -v to see a list of the files searched for.
  |
1 | import System.Random
  | ^^^^^^^^^^^^^^^^^^^^

但是,如果我返回 GHCi,我可以输入 :load test.hs。这有效,并允许我生成随机数。

当我 运行 ghc-pkg check 时,我只收到有关缺少黑线鳕接口文件的警告:https://pastebin.com/6a9f0nYZ。据我了解,这与当前问题无关。

此外,当我运行 ghc-pkg list时,random-1.1在列表中,所以应该安装random

几个问题:


编辑:GHC 和 GHCi 是同一版本。

$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.6.4
$ ghci --version
The Glorious Glasgow Haskell Compilation System, version 8.6.4

编辑:ghcghci 都在 /usr/bin/

$ which ghc
/usr/bin/ghc
$ which ghci
/usr/bin/ghci

更新: 看起来这是 Arch Linux 的特性,而不是损坏的包。我已经相应地更新了我的答案。

GHCi 加载 "dynamic" 版本的模块。默认情况下,GHC 链接 "static" 版本的模块。特别是,当您 运行:

> import System.Random

在 GHCi 下,它会尝试访问文件 Random.dyn_hi 以获取模块的接口信息。相反,当您编译一个包含该 import 语句的文件时,GHC 会尝试访问该文件 Random.hi.

您可以通过 运行ning ghc-pkg field random import-dirs 并查看生成的目录来验证这是问题所在。应该有一个 System 子目录,里面通常有两个文件:System.hiSystem.dyn_hi。如果缺少前者,那是你的问题。

现在,您可能正在使用 Arch Linux。正如 "Problems with linking" 部分中关于 Arch Haskell wiki page 的文档所述,Arch Haskell 社区包(包括 haskell-random)有意省略了接口文件和库的静态版本。

那里给出了几种解决方法:

  • 您可以在使用 GHC 编译时使用动态链接。直接使用 GHC 时,这仅意味着传递 -dynamic 标志。对于基于 Cabal 的项目,该页面上给出了修改 ~/.cabal/config 以对所有项目使用动态链接的说明。
  • 您可以安装 ghc-staticghc-pristine 包并设置路径 and/or Cabal 以使用 /usr/share/ghc-pristine/bin/ghc 中的编译器,它将维护自己独立的包数据库不会干扰全局安装的 Haskell 社区包,例如 haskell-random.
  • 您可以安装 ghc-static 以获得基础库的静态版本,然后 运行 cabal install --force-reinstalls somepackage 获取您需要的所有非基础包。请注意,Wiki 指出这可能既乏味又复杂,因为您必须手动确定所有包依赖项。

现在,看起来您已经安装了 ghc-static,或者在调用 GHC 时您会 收到有关 [=32= 中丢失文件的错误] 包裹。你 运行 cabal install --force-reinstalls random,尽管正如@dfeuer 指出的那样,运行:

可能更安全
$ cabal install --force-reinstalls random-1.1

以确保重新安装相同的版本。

无论如何,这会在您的用户特定包目录中安装一个额外的 random 副本。如果你 运行:

$ ghc-pkg list

您会看到 random-1.1 同时列在全局数据库和用户数据库下:

/usr/lib/ghc-8.6.4/package.conf.d
    ...
    random-1.1
    ...
/home/xxxx/.ghc/x86_64-linux-8.6.4/package.conf.d
    random-1.1

如果你 运行:

$ ghc-pkg describe random

您会看到它列出了两个单独的已安装版本,这就是为什么您现在使用 ghc-pkg field random import-dirs.

获得重复字段的原因

这应该没有什么问题。您的用户数据库将优先于全局数据库,因此当您 运行 GHCi 或 GHC 时,将使用您新安装的 random 版本。

请注意,如果您改变主意并想要取消此重新安装(并可能尝试 Wiki 上建议的其他解决方案之一),您应该能够 运行:

$ ghc-pkg unregister --user random

从技术上讲,这实际上并不会删除软件包(因为编译后的版本仍将存在于 ~/.cabal/lib 下),但它应该会恢复原样。