views:

144

answers:

2
+3  Q: 

haskell global var

The task is to create dynamically linked library, which encapsulates database hard work. Due to some design limitations I have a defined interface, which consist of numerous functions. Each function takes a parameters and use them in database query. Database connection should be inside dll and application don't want to bother is there any connection.

What is the best way to initialize db connection and then give it to every function without passing it around explicitly.

Of course in general I'd like to use State monad. But dll is not provided to have one entry point.

+1  A: 

You can "cheat" using unsafePerformIO:

globalVar :: MVar Integer
globalVar = unsafePerformIO (newMVar 17)

My condolences for the fixed API.

yairchu
+1  A: 

It sounds like you are trying to create a DLL that can be called from other languages. If so then all your functions will live in the IO monad. So you can use an IORef to store the database connection object.

Updated (see comments below)

GHC has a similar problem with the global random number generator state. Here is the relevant source code from System.Random:

-- |Gets the global random number generator.
getStdGen :: IO StdGen
getStdGen  = readIORef theStdGen

theStdGen :: IORef StdGen
theStdGen  = unsafePerformIO $ do
   rng <- mkStdRNG 0
   newIORef rng

So presumably something similar would work for the DB connection. Yes, this is using the evil unsafePerformIO, but sometimes you just gotta be evil.

Paul Johnson
@Paul Johnson: if he was designing his own interface, he could have a session parameter to his functions that holds this `IORef`. the problem is that he needs to implement a specific API where he can't be giving the IORef to the functions, so he needs some way to share a global IORef
yairchu
@Pail Jounson: confirming. your answer is good, is everything would be called from entry point.
Vasiliy Stavenko