任务是创建动态链接库,它封装了数据库的辛勤工作。由于一些设计上的限制,我有一个定义好的界面,它由许多功能组成。每个函数都接受一个参数并在数据库查询中使用它们。数据库连接应该在DLL里面,应用程序不想打扰有没有连接。haskell global var
什么是最好的方式来初始化数据库连接,然后把它给每个函数,而不明确传递它。
当然,一般来说我想使用状态monad。但是dll的设计并不是有一个入口点。
任务是创建动态链接库,它封装了数据库的辛勤工作。由于一些设计上的限制,我有一个定义好的界面,它由许多功能组成。每个函数都接受一个参数并在数据库查询中使用它们。数据库连接应该在DLL里面,应用程序不想打扰有没有连接。haskell global var
什么是最好的方式来初始化数据库连接,然后把它给每个函数,而不明确传递它。
当然,一般来说我想使用状态monad。但是dll的设计并不是有一个入口点。
可以 “欺骗” 使用unsafePerformIO
:
{-# NOINLINE globalVar #-}
globalVar :: MVar Integer
globalVar = unsafePerformIO (newMVar 17)
我对固定API慰问。
这听起来像你正试图创建一个可以从其他语言调用的DLL。如果是这样,那么你的所有函数将存在于IO monad中。所以你可以使用IORef来存储数据库连接对象。
更新(见下面的评论)
GHC与全球随机数发生器状态类似的问题。下面是从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
所以大概类似的东西会为DB连接工作。是的,这是使用邪恶不安全的PERFORMIO,但有时你只是邪恶。
@Paul Johnson:如果他设计自己的界面,他可以为他的函数拥有一个会话参数来保存这个'IORef'。问题在于他需要实施特定的API,因为他不能将IORef授予职能,所以他需要某种方式来共享全球IORef – yairchu 2009-12-10 14:33:38
@Paul Jounson:确认。你的回答是好的,是从入口点召唤一切。 – 2009-12-10 21:31:53
我不确定你的意思是“dll没有提供一个入口点”。你能否扩大?使用monad来处理这些事情通常更健壮和更好。 – svenningsson 2009-12-09 12:09:19
应该提供几个独立的功能。其中两个'init'&'close', 其他的是数据获取器和数据库更新器。 并且所有函数都不应该直接处理数据库处理程序。 – 2009-12-09 23:46:29