如何在ghci中正确使用PackageImports?

3
我想在ghci中进行测试,但我遇到了不同包中同名模块的问题(这基本上是我之前的一个问题的延续:如果两个模块共享相同的名称应该怎么办?)。
涉及的软件包是crypto-apicryptoniteDRBG。它们都提供涉及Crypto.Random的模块。我在ghci中使用PackageImports来解决这个问题。
然而,似乎使用PackageImports的顺序很重要。
这个可以在ghci中工作:
:set -XPackageImports
import Crypto.Random.DRBG
import "crypto-api" Crypto.Random

这种方法行不通:

:set -XPackageImports
import "crypto-api" Crypto.Random
import Crypto.Random.DRBG  -- Error!

此外,这个也不起作用:
:set -XPackageImports
import "crypto-api" Crypto.Random
import "DRBG" Crypto.Random.DRBG -- Error!

出现的错误是:
<interactive>:1:1: error:
Ambiguous interface for ‘Crypto.Random’:
  it was found in multiple packages:
  crypto-api-0.13.2 cryptonite-0.23

我做错了什么还是这是一个bug?

错误信息是什么?使用“import Mod as Foo”方法给三个模块不同的名称如何?只是猜测。 - Johnny Liao
@JohnnyLiao,我添加了我收到的错误信息。我还尝试使用“as”导入模块,但是我收到了相同的错误信息。 - user668074
2个回答

1
也许最简单的方法是避免使用PackageImports,而是在启动ghci时重命名包,使用-package选项:
ghci -package "crypto-api (Crypto.Random as A)" -package "cryptonite (Crypto.Random as B)"

进入ghci后,您可以导入已重命名的模块:

Prelude> import A
Prelude A> import B
Prelude A B>

语法-package "crypto-api (Crypto.Random as A)"仅使Crypto.Random模块在ghci中可用,但不包括包中的其他模块。
根据GHC用户指南中Thinning and renaming modules部分的描述:

我们还支持重命名模块,以便您需要同时引用两个模块;这可以通过编写OldModName as NewModName来支持,例如-package "base (Data.Bool as Bool)。您还可以编写 -package "base with (Data.Bool as Bool) 以包括所有原始绑定(例如,重命名严格是附加的)。

因此,也许更好的写法是像-package "crypto-api with (Crypto.Random as A)"这样的选项,以保持对所有模块的访问。
使用PackageImports代替减少和重命名模块存在问题,它使源代码依赖于导入模块所在的精确包。如果一个模块更改了包,那么程序就会出错。

0

你为什么会期望那个能够正常工作呢?

:set -XPackageImports
import "crypto-api" Crypto.Random
import Crypto.Random.DRBG  -- Error!
import "DRBG" Crypto.Random.DRBG -- Error!

您已经从同一个包中两次导入了DRBG模块。根据您的问题,我认为您想从crypto-api和cryptonite获取Crypto.Random模块,但是我在这里没有看到任何尝试使用cryptonite。

只是为了明确起见,我可以通过GHCi重现我认为您遇到的错误:

Prelude> :set -XPackageImports
Prelude> import "crypto-api" Crypto.Random as OriginalRandom
Prelude OriginalRandom> import "cryptonite" Crypto.Random as ConflictRandom

<interactive>:1:1: error:
    Ambiguous module name ‘Crypto.Random’:
      it was found in multiple packages:
      crypto-api-0.13.2 cryptonite-0.24

但是当您从文件中加载它时,所有内容都可以正常工作,因此这只是一个错误,可以避免:

% cat t.hs
{-# LANGUAGE PackageImports #-}

import "crypto-api" Crypto.Random as OriginalRandom
import "cryptonite" Crypto.Random as ConflictRandom
import Crypto.Random.DRBG -- This only appears in one package
% ghci t.hs
GHCi, version 8.2.1: http://www.haskell.org/ghc/  :? for help
Loaded GHCi configuration from /Users/tommd/.ghci
[1 of 1] Compiling Main             ( t.hs, interpreted )
Ok, 1 module loaded.
*Main>

请注意,DRBG不是本讨论的一部分。据我所知,它与Hackage上的任何内容都没有冲突的模块名称。

我编辑了我的初始问题,因为我猜我没有写清楚。我不是试图两次导入DRBG,我只是想展示使用PackageImports导入DRBG的两种方式都不起作用。cryptonite包与错误没有直接关系,但我之所以首先使用PackageImports的原因是cryptonitecrypto-api具有共享模块名称,所以我认为值得一提。我知道我可以从文件中导入它们,但我想知道是否可以在ghci中完成此操作而不会导致错误。 - user668074

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接