为什么 GHCi 可以理解导入而 GHC 不能?

Fin*_*inn 5 haskell ghc ghci

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

\n\n

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

\n\n
test.hs:1:1: error:\n    Could not find module \xe2\x80\x98System.Random\xe2\x80\x99\n    There are files missing in the \xe2\x80\x98random-1.1\xe2\x80\x99 package,\n    try running \'ghc-pkg check\'.\n    Use -v to see a list of the files searched for.\n  |\n1 | import System.Random\n  | ^^^^^^^^^^^^^^^^^^^^\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

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

\n\n

另外,当我运行时ghc-pkg listrandom-1.1位于列表中,因此random应该安装。

\n\n

有几个问题:

\n\n
    \n
  • 为什么 GHC 和 GHCi 可以访问不同的导入?为什么系统要这样设置呢?也许我只是不明白GHC和GHCi之间的关系。
  • \n
  • 根据错误消息,“文件丢失”。我怎样才能找出哪些文件?
  • \n
  • 我怎样才能编译使用的Haskell文件System.Random
  • \n
\n\n
\n\n

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

\n\n
$ ghc --version\nThe Glorious Glasgow Haskell Compilation System, version 8.6.4\n$ ghci --version\nThe Glorious Glasgow Haskell Compilation System, version 8.6.4\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

编辑: 和 都ghcghci/ usr/bin/中

\n\n
$ which ghc\n/usr/bin/ghc\n$ which ghci\n/usr/bin/ghci\n
Run Code Online (Sandbox Code Playgroud)\n

K. *_*uhr 3

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

GHCi 加载模块的“动态”版本。默认情况下,GHC 与模块的“静态”版本链接。特别是,当您运行时:

> import System.Random
Run Code Online (Sandbox Code Playgroud)

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

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

现在,看起来您可能正在使用 Arch Linux。正如 Arch Haskell wiki 页面“链接问题”部分中所述,Arch Haskell 社区包(包括haskell-random)有意省略接口文件和库的静态版本。

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

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

现在,看起来您已经ghc-static安装了,或者在调用 GHC 时,您还会收到有关包中缺少文件的错误base。你运行了cabal install --force-reinstalls random,尽管正如 @dfeuer 指出的那样,运行可能更安全:

$ cabal install --force-reinstalls random-1.1
Run Code Online (Sandbox Code Playgroud)

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

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

$ ghc-pkg list
Run Code Online (Sandbox Code Playgroud)

您将看到它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
Run Code Online (Sandbox Code Playgroud)

如果你运行:

$ ghc-pkg describe random
Run Code Online (Sandbox Code Playgroud)

您会看到它列出了两个单独的安装版本,这就是为什么您现在会收到重复字段的原因ghc-pkg field random import-dirs

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

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

$ ghc-pkg unregister --user random
Run Code Online (Sandbox Code Playgroud)

从技术上讲,这实际上不会删除该包(因为编译后的版本仍位于 下~/.cabal/lib),但它应该使事情恢复原状。