Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why am I able to use my value constructor even though I don't export it?

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?

like image 612
jub0bs Avatar asked Jan 23 '15 18:01

jub0bs


1 Answers

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.

like image 81
Daniel Wagner Avatar answered Nov 20 '22 12:11

Daniel Wagner