For practice, I'm implementing a queue data type in a module called "Queue". My data type is also called "Queue", as is its only value constructor:
module Queue (Queue, enq, emptyQueue) where
data Queue a = Queue {
inbox :: [a],
outbox :: [a]
} deriving (Eq, Show)
emptyQueue :: Queue a
emptyQueue = Queue [] []
enq :: a -> Queue a -> Queue a
enq x (Queue inb out) = Queue (x:inb) out
-- other function definitions (irrelevant here)...
As far as I understand, because I wrote Queue
, not Queue(..)
or Queue(Queue)
in the export statement, I don't expect the value constructor of my data type to be exported by the module. This is exactly what I want, for encapsulation purposes: users should not be able to use the value constructor directly; only emptyQueue
, enq
, and the other functions in my interface.
However (and the solution to my problem may be obvious to seasoned Haskellers), if I load my module in GHCi, I'm able to use the value constructor directly.
$ ghci Queue.hs
GHCi, version 7.8.4: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
[1 of 1] Compiling Queue ( Queue.hs, interpreted )
Ok, modules loaded: Queue.
λ> Queue [1] [2]
Queue {inbox = [1], outbox = [2]}
As stated above, this is undesirable. What am I doing wrong?
You are doing nothing wrong. It's just that, for convenience, ghci ignores scoping rules on modules it loads.
If you want to see what would normally be available, you can
:m -Queue
:m +Queue
You can later return to the "everything is available" mode with
:m *Queue
See also What's really in scope at the prompt? in the official documentation.
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