I explored System.Random.StdGen and saw this code in the source.
data StdGen = StdGen Int32 Int32
It seems the module export StdGen too.
module System.Random (
RandomGen(next, split, genRange)
, StdGen
...
However, why can't I do this in my code, say like,
Prelude System.Random> StdGen 1 2
Not in scope: data constructor `System.Random.StdGen'**
In the other hand, I can do this,
module F (Foo) where
import GHC.Int
data Foo = Foo GHC.Int.Int32 GHC.Int.Int32 deriving (Show)
and
Prelude> Foo 1 2
Foo 1 2
Would someone please kindly tell me how actually this data constructor is hidden?
Data constructors are first class values in Haskell and actually have a type. For instance, the type of the Left constructor of the Either data type is: Left :: a -> Either a b. As first class values, they may be passed to functions, held in a list, be data elements of other algebraic data types and so forth.
Maybe is a type constructor because it is used to construct new types (the result type depends on the type of a in Maybe a ), where such a type might be Maybe Int (notice, there's no type param a anymore, i.e. all type parameters are bound).
IO is a type constructor, not a value constructor. IO True would be a type, not a value (if True was a type).
There are two things to understand here. Export syntax and a difference in GHCi behaviour between compiled and interpreted values.
Exporting from a module using this syntax
module System.Random (
-- ...
, StdGen
-- ...
tells GHC only to export the datatype, not the constructor (even if both have the same name). The constructor can be listed explicitly within parentheses after the datatype name if you want to export it, like this:
StdGen(StdGen)
Or you can export a datatype with all its constructors like this:
StdGen(..)
In addition, GHCi, when loading an interpreted module, always allows you to see all the entities visisble at the top-level of the module, even if they're hidden by the export list. This is to facilitate development and debugging, and is the reason why your Foo
is visible.
This mode where "everything" is visible is reflected by putting a *
in front of the module name at the GHCi prompt. If there's a *
, everything is visisble, and if not, then the exported entities are visible.
When using the :m
command to add or remove modules from scope, you can select whether you want to add modules in *
-form or not.
But for compiled modules (and a library module like System.Random
usually is compiled), the *
-form is not available, so for these you'll always be in the situation that the export list is respected.
See the documentation for a full description of the scoping behaviour of GHCi.
If you look at the sources, you'll see something along the lines of:
module System.Random
(
-- stuff...
, StdGen
-- even more stuff...
)
This syntax means that only the type is exported, not its constructor(s). If you want to export the constructor too, you'd do:
module System.Random
( StdGen(..)
-- ...
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With