2009-12-09 6 views
4

La tâche consiste à créer une bibliothèque liée dynamiquement, qui encapsule le travail de base de données. En raison de certaines limitations de conception, j'ai une interface définie, qui consiste en de nombreuses fonctions. Chaque fonction prend un paramètre et les utilise dans une requête de base de données. La connexion à la base de données devrait être dans la DLL et l'application ne veut pas déranger s'il y a une connexion.haskell global var

Quelle est la meilleure façon d'initialiser la connexion db, puis de la donner à chaque fonction sans la transmettre explicitement.

Bien sûr, en général, j'aimerais utiliser la monade d'État. Mais DLL n'est pas conçu pour avoir un point d'entrée.

+1

Je ne suis pas sûr de ce que vous voulez dire par "dll n'est pas prévu pour avoir un point d'entrée". Pourriez-vous s'il vous plaît développer? Utiliser une monade pour prendre soin de ces choses est généralement beaucoup plus robuste et plus agréable. – svenningsson

+0

Il existe plusieurs fonctions indépendantes devraient être fournies. deux d'entre eux 'init' &' close', autres sont des getters de données et mise à jour de base de données. Et toutes les fonctions ne doivent pas traiter directement avec le gestionnaire de base de données. –

Répondre

1

Vous pouvez "tricher" en utilisant unsafePerformIO:

{-# NOINLINE globalVar #-} 
globalVar :: MVar Integer 
globalVar = unsafePerformIO (newMVar 17) 

Mes condoléances pour l'API fixe.

+1

Ceci est dangereux sans NOINLINE - voir http://neilmitchell.blogspot.ch/2014/10/hlint-now-spots-bad-unsafeperformio.html. – ron

+0

@ron: merci. fixe – yairchu

2

Il semble que vous essayez de créer une DLL qui peut être appelée à partir d'autres langues. Si oui, alors toutes vos fonctions vivront dans la monade IO. Vous pouvez donc utiliser un IORef pour stocker l'objet de connexion à la base de données.

Mise à jour (voir les commentaires ci-dessous)

GHC a un problème similaire avec l'état global du générateur de nombres aléatoires. Voici le code source correspondant de 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 

Ainsi serait sans doute quelque chose de semblable travail pour la connexion DB. Oui, c'est en utilisant le mauvais dangerPerformIO, mais parfois vous devez juste être mauvais.

+0

@Paul Johnson: s'il créait sa propre interface, il pourrait avoir un paramètre de session à ses fonctions qui contient ce 'IORef'. le problème est qu'il doit implémenter une API spécifique où il ne peut pas donner l'IORef aux fonctions, donc il a besoin d'un moyen de partager un IORef global – yairchu

+0

@Pail Jounson: confirmant. votre réponse est bonne, tout serait appelé depuis le point d'entrée. –