Happstackで作業するときはいつものように、ハンドラーに使用する独自のサーバーモナドを作成し、DBとセッション、およびいくつかのエラー処理をカバーしています。私は最近happstack-clientsession
、大きな助けになり、自分のソリューションを書くのを妨げる-Packageを発見しました。
ClientSessionT
モナドで自分自身に配線するのに少し問題がありますが。結局のところ、そのためのインスタンスはMonadReader
ないMonadError
ので、ラッパーモナドでインスタンス化することはできません。
モジュールの完全なコードは次のとおりです。
{-# 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
)を理解することができなかったので、この特定の問題をカバーし、それが一般的にどのように行われるのかを教えてくれる答えが欲しいです。