12

我探索了 System.Random.StdGen 并在源代码中看到了这段代码。

data StdGen = StdGen Int32 Int32

似乎模块也导出了 StdGen。

module System.Random (

    RandomGen(next, split, genRange)

    , StdGen

    ...

但是,为什么我不能在我的代码中这样做,比如,

Prelude System.Random> StdGen 1 2

Not in scope: data constructor `System.Random.StdGen'**

另一方面,我可以做到这一点,

module F (Foo) where

    import GHC.Int

    data Foo = Foo GHC.Int.Int32 GHC.Int.Int32 deriving (Show)

Prelude> Foo 1 2

Foo 1 2

有人能告诉我这个数据构造函数是如何隐藏的吗?

4

2 回答 2

22

这里有两点需要理解。导出语法和编译值和解释值之间 GHCi 行为的差异。

导出语法

使用此语法从模块导出

module System.Random (
    -- ...
    , StdGen
    -- ...

告诉 GHC 只导出数据类型,而不是构造函数(即使两者具有相同的名称)。如果要导出构造函数,可以在数据类型名称后的括号内显式列出,如下所示:

    StdGen(StdGen)

或者,您可以导出具有所有构造函数的数据类型,如下所示:

    StdGen(..)

GHCI 行为

此外,GHCi 在加载解释模块时,始终允许您查看模块顶层可见的所有实体,即使它们被导出列表隐藏。Foo这是为了方便开发和调试,也是你可见的原因。

这种“一切”可见的模式通过*在 GHCi 提示符的模块名称前面放置一个来反映。如果有*,则一切都是可见的,如果没有,则导出的实体是可见的。

使用:m命令在作用域中添加或删除模块时,您可以选择是否要在*-form 中添加模块。

但是对于已编译的模块(以及System.Random通常已编译的库模块),- *form 不可用,因此对于这些,您将始终处于导出列表受到尊重的情况。

有关 GHCi 作用域行为的完整描述,请参阅文档

于 2013-03-07T14:53:48.690 回答
8

如果您查看 sources,您会看到以下内容:

module System.Random
    (
    -- stuff...
    , StdGen
    -- even more stuff...
    )

此语法意味着仅导出类型,而不导出其构造函数。如果你也想导出构造函数,你会这样做:

module System.Random
    ( StdGen(..)
    -- ...
    )
于 2013-03-07T14:41:06.787 回答