Как Haskell скрывает конструктор данных?

Я изучил 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

Кто-нибудь, пожалуйста, сообщите мне, как на самом деле этот конструктор данных скрыт?

Ответ 1

Здесь есть две вещи. Экспорт синтаксиса и различие в поведении GHCi между скомпилированными и интерпретируемыми значениями.

Синтаксис экспорта

Экспорт из модуля с использованием этого синтаксиса

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

указывает GHC только экспортировать тип данных, а не конструктор (даже если оба имеют одинаковое имя). Конструктор может быть указан явно в круглых скобках после имени типа данных, если вы хотите экспортировать его, например:

    StdGen(StdGen)

Или вы можете экспортировать тип данных со всеми его конструкторами, такими как:

    StdGen(..)

поведение GHCi

Кроме того, GHCi при загрузке интерпретируемого модуля всегда позволяет видеть все объекты, видимые на верхнем уровне модуля, даже если они скрыты в списке экспорта. Это облегчает разработку и отладку, и именно поэтому ваш Foo виден.

Этот режим, в котором отображается "все", отражается, помещая * перед именем модуля в приглашении GHCi. Если есть *, все будет видимым, а если нет, то экспортируемые объекты будут видны.

При использовании команды :m для добавления или удаления модулей из области видимости вы можете выбрать, хотите ли вы добавлять модули в * -form или нет.

Но для скомпилированных модулей (и обычно компилируется библиотечный модуль, например System.Random) форма * недоступна, поэтому для них вы всегда будете в ситуации, когда соблюдается список экспорта.

См. документацию для полного описания поведения области действия GHCi.

Ответ 2

Если вы посмотрите на источники, вы увидите что-то по строкам:

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

Этот синтаксис означает, что экспортируется только тип, а не его конструктор (ы). Если вы также хотите экспортировать конструктор, выполните следующие действия:

module System.Random
    ( StdGen(..)
    -- ...
    )