[Haskell-cafe] Mixing internal functions and datatypes with
externally available ones
lrpalmer at gmail.com
Sun Dec 27 13:35:40 EST 2009
On Sun, Dec 27, 2009 at 5:51 AM, DPX-Infinity <dpx.infinity at gmail.com> wrote:
> I'm writing a library - some kind a wrapper around SDL library, an engine.
> For example, I have a module Graphics.UI.SDL.XEngine.State and
> functions modifyState and setColor in it. These functions are using
> "global" variable of type IO (IORef XState). I want to use the first
> function in Graphics.UI.SDL.XEngine.General and
> Graphics.UI.SDL.XEngine.Drawing modules and I don't want this function
> to be accessible from a program which uses my library, but I need to
> make the function setColor visible from everywhere. Is there a simple
> way to do such thing? Or maybe I should restructure my library?
Well you should definitely restructure your library. Global variables
in other languages are looked down upon (and they invented the
"singleton" pattern to justify their sin), but in Haskell they are
simply not acceptable. Haskell functions have the beautiful property
that they work just as well in my program as in yours -- they make no
reference to the context in which they exist. A global variable
breaks this property.
Anyway, it sounds like you may not have one anyway. A value of type
IO (IORef ...) is not a variable, but an action returning a mutable
cell. So if you have something like:
foo :: IO (IORef Int)
foo = newIORef 10
Each time foo is bound it will return a fresh variable with initial
value 10. And this is perfectly acceptable Haskell (because it is not
global state), but probably not what you wanted.
Anyway, to get the accessibility you are going for, you should not
expose General in your library interface (you can specify which
modules are exposed in your cabal file). Use General within your
library, and write another module that is exposed and that re-exports
what you want users to be able to see.
Does that make sense?
More information about the Haskell-Cafe