正如我在使用Happstack時通常那樣,我一直在使用自己的服務器monad用於處理程序,用於覆蓋我的數據庫和會話以及一些錯誤處理。我最近發現了happstack-clientsession
-Package是一個很大的幫助,並且阻止我編寫自己的解決方案。將MonadReader/MonadError實例添加到Transformer類型
雖然在我自己的ClientSessionT
monad中有一點麻煩。事實證明,它沒有MonadReader
或MonadError
實例,所以我不能在我的包裝monad中將它們實例化。
這裏是模塊的全碼:
{-# LANGUAGE OverloadedStrings, GeneralizedNewtypeDeriving, DeriveDataTypeable, EmptyDataDecls, TemplateHaskell #-}
module Server where
import Control.Monad
import Control.Monad.Error
import Control.Monad.Reader
import Control.Monad.Trans
import Data.Data (Data, Typeable)
import Data.SafeCopy (base, deriveSafeCopy)
import Database.MongoDB as M
import Happstack.Server
import Happstack.Server.Error
import Happstack.Server.ClientSession
import System.IO.Pool
import System.IO.Error
import Web.ClientSession (getDefaultKey)
type MongoPool e = Pool e Pipe
data PonySession = PonySession -- TODO: Fill in User type when available
deriving (Ord, Read,Show, Eq, Typeable, Data)
$(deriveSafeCopy 0 'base ''PonySession)
instance ClientSession PonySession where
empty = PonySession
newtype PonyServerPartT e m a = PonyServerPart (ClientSessionT PonySession (ReaderT (MongoPool IOError) (ServerPartT (ErrorT e m))) a)
deriving (Monad, MonadIO, MonadReader (MongoPool e), MonadError e, ServerMonad, MonadPlus)
type PonyServerPart = PonyServerPartT IOError IO
runServerT s = mapServerPartT' (spUnwrapErrorT errorHandler) $ do
key <- liftIO getDefaultKey
let sessConf = (mkSessionConf key) { sessionCookieLife = MaxAge $ 60 * 60 * 24 * 7 }
pool <- liftIO mongoPool
runReaderT (runClientSessionT s sessConf) pool
where errorHandler = simpleErrorHandler . show
mongoPool :: IO (MongoPool IOError)
mongoPool = newPool fac 10
where fac = Factory {
newResource = connect $ M.host "127.0.0.1",
killResource = close,
isExpired = isClosed
}
我得到的錯誤是顯而易見的:從MonadError
和MonadReader
,導出不起作用。但我需要這些,否則整個表演都是沒用的。
由於我從來沒有能夠弄清楚這些是如何完成的(並依靠deriving
),我想要一個涵蓋這個特定問題的答案,並告訴我它是如何完成的。
我知道爲什麼會發生這種錯誤,我在我的問題中已經說過。我的實際問題是如何爲這個特定的monad類型添加這些實例。 – Lanbo 2012-04-22 11:11:15