Haskell如何隐藏数据构造函数?

Zna*_*atz 12 constructor haskell system

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

data StdGen = StdGen Int32 Int32
Run Code Online (Sandbox Code Playgroud)

模块似乎也出口了StdGen.

module System.Random (

    RandomGen(next, split, genRange)

    , StdGen

    ...
Run Code Online (Sandbox Code Playgroud)

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

Prelude System.Random> StdGen 1 2

Not in scope: data constructor `System.Random.StdGen'**
Run Code Online (Sandbox Code Playgroud)

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

module F (Foo) where

    import GHC.Int

    data Foo = Foo GHC.Int.Int32 GHC.Int.Int32 deriving (Show)
Run Code Online (Sandbox Code Playgroud)

Prelude> Foo 1 2

Foo 1 2
Run Code Online (Sandbox Code Playgroud)

请有人请告诉我这个数据构造函数实际上是如何隐藏的?

kos*_*kus 22

这里有两件事要理解.导出语法以及编译和解释值之间GHCi行为的差异.

导出语法

使用此语法从模块导出

module System.Random (
    -- ...
    , StdGen
    -- ...
Run Code Online (Sandbox Code Playgroud)

告诉GHC只导出数据类型,而不是构造函数(即使两者都有相同的名称).如果要导出构造函数,可以在数据类型名称后面的括号中明确列出,如下所示:

    StdGen(StdGen)
Run Code Online (Sandbox Code Playgroud)

或者您可以导出一个数据类型及其所有构造函数,如下所示:

    StdGen(..)
Run Code Online (Sandbox Code Playgroud)

GHCi的行为

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

"一切"可见的模式通过*在GHCi提示符下放置模块名称来反映.如果有*,那么一切都是可见的,如果没有,那么导出的实体是可见的.

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

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

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


Nik*_* B. 8

如果你看一下这些来源,你会看到以下内容:

module System.Random
    (
    -- stuff...
    , StdGen
    -- even more stuff...
    )
Run Code Online (Sandbox Code Playgroud)

此语法意味着仅导出类型,而不是其构造函数.如果你也想导出构造函数,你可以:

module System.Random
    ( StdGen(..)
    -- ...
    )
Run Code Online (Sandbox Code Playgroud)