2011-10-18 35 views
5

我想創建一個Happstack應用程序,可以訪問數據庫。我認爲,一個單子堆棧與IO在底部和頂部的數據庫寫入般的單子(在中間日誌作家)將努力在每個接入,例如一個明確的功能:如何在Happstack中創建數據庫Monad堆棧?

itemsRequest :: ServerConfig -> ServerPart Response 
itemsRequest cf = dir "items" $ do 
    methodM [GET,HEAD] 
    liftIO $ noticeM (scLogger cf) "sended job list" 

    items <- runDBMonad (scDBConnString cf) $ getItemLists 

    case items of 
    (Right xs) -> ok $ toResponse $ show xs 
    (Left err) -> internalServerError $ toResponse $ show err 

用:

getItemList :: MyDBMonad (Error [Item]) 
getItemList = do 
    -- etc... 

但我有單子和單子變形金剛(我認爲這個問題作爲一個練習來學習一下吧)的小知識,我不知道如何開始數據庫單子的創建,如何解除IO從happstack到數據庫堆棧,等等。

+0

我試着用'unsafePerformIO'來做IO。因爲Happstack使用純粹的組合,也許這是你做IO的唯一方法。 – Nybble

+0

@吳興波,可以用liftIO在happstack上做IO,但是我不知道是誰傳給另一個monad棧。 – Zhen

回答

6

你可能想用「ReaderT」:

type MyMonad a = ReaderT DbHandle ServerPart a 

Reader單子轉換使得使用ask功能來訪問一個值 - 在這種情況下,我們希望每個人都能得到的值是數據庫連接。

在這裏,DbHandle是一些連接到您的數據庫。

因爲'ReaderT'已經是所有happstack-server類型類的一個實例,所有正常的happstack-server函數都可以在這個monad中工作。

您可能還需要某種形式的幫助來打開和關閉數據庫連接:

runMyMonad :: String -> MyMonad a -> ServerPart a 
runMyMonad connectionString m = do 
    db <- liftIO $ connect_to_your_db connectionString 
    result <- runReaderT m db 
    liftIO $ close_your_db_connection db 

(這可能是最好使用像「支架」這裏的功能,但我不知道有是ServerPart單元的這種操作)

我不知道你想如何做日誌記錄 - 你打算如何與你的日誌文件交互?喜歡的東西:

type MyMonad a = ReaderT (DbHandle, LogHandle) ServerPart a 

然後:

askDb :: MyMonad DbHandle 
askDb = fst <$> ask 

askLogger :: MyMonad LogHandle 
askLogger = snd <$> ask 

可能就足夠了。然後,您可以在這些基元上構建高級函數。無論如何,您還需要更改runMyMonad以通過LogHandle

一旦你得到兩個以上的東西你想訪問它支付有一個正確的記錄類型,而不是一個元組。

+2

Side topic:連接池有http://hackage.haskell.org/package/resource-pool和http://hackage.haskell.org/package/pool。不過,這可能比你需要的要多。 –

+0

感謝您的游泳池提示! – Zhen

6

下面是一些最小工作代碼,從上面的代碼片段爲像我這樣的困惑新手編譯。

你把東西放入AppConfig類型,並在響應制造商裏面用ask抓住它。

{-# LANGUAGE OverloadedStrings #-} 
module Main where 

import Happstack.Server 
import Control.Monad.Reader 
import qualified Data.ByteString.Char8 as C 

myApp :: AppMonad Response 
myApp = do 
    -- access app config. look mom, no lift! 
    test <- ask 

    -- try some happstack funs. no lift either. 
    rq <- askRq 
    bs <- lookBS "lol" 

    -- test IO please ignore 
    liftIO . print $ test 
    liftIO . print $ rq 
    liftIO . print $ bs 

    -- bye 
    ok $ toResponse ("Oh, hi!" :: C.ByteString) 

-- Put your stuff here. 
data AppConfig = AppConfig { appSpam :: C.ByteString 
          , appEggs :: [C.ByteString] } deriving (Eq, Show) 
config = AppConfig "THIS. IS. SPAAAAAM!!1" [] 

type AppMonad = ReaderT AppConfig (ServerPartT IO) 

main = simpleHTTP (nullConf {port=8001}) $ runReaderT myApp config {appEggs=["red", "gold", "green"]}