我读过 Happstack 速成课程。我的 Web 服务器几乎与透明地传递多个 AcidState 句柄部分中描述的完全相同
我的问题是,我有非酸性的值,但想在 Happstack 应用程序中访问。具体来说,来自push-notify-general library 的“PushManager” ,
我想要的是:
data Acid = Acid
{ acidCountState :: AcidState CountState
, acidGreetingState :: AcidState GreetingState
, acidPushManager :: AcidState PushManager
}
我无法完成这项工作,因为 1) PushManager 在内部使用了如此多的数据类型,并且通过调用 $(deriveSafeCopy ...) 来使底层数据类型 SafeCopy 兼容是不现实/不可靠的。2) PushManager 不仅包含简单的值,而且还包含与 SafeCopy 兼容的功能。
我尝试的另一件事是“Acid”数据声明不仅包含 AcidState,还包含非 AcidState 数据。通过查看runApp的定义,“Acid”只是用于Reading,所以我认为用State monad重写可能能够满足我的需要。——但事实证明,事情并没有那么简单。我的暂定代码是:
{-# LANGUAGE MultiParamTypeClasses, GeneralizedNewtypeDeriving,
TemplateHaskell, TypeFamilies, DeriveDataTypeable,
FlexibleContexts, ScopedTypeVariables,
NamedFieldPuns, DeriveFunctor, StandaloneDeriving, OverloadedStrings #-}
import Control.Applicative ( Applicative, Alternative, (<$>))
import Control.Monad ( MonadPlus )
import Control.Monad.State.Strict ( MonadState, StateT, get, put, evalStateT )
import Control.Monad.Trans ( MonadIO )
import Data.Acid
import Data.Data ( Data, Typeable )
import Happstack.Server
newtype Simple a = Simple { unSimple :: a }
deriving (Show)
data CountState = CountState { count :: Integer }
deriving (Eq, Ord, Data, Typeable, Show)
-- This data is equivalent to the one previously called "Acid"
data States = States {
simpleState :: Simple Int
, acidCountState :: AcidState CountState
}
initialStates :: States
initialStates = States { simpleState = Simple 1, acidCountState = undefined }
newtype App a = App { unApp :: ServerPartT (StateT States IO) a }
deriving ( Functor, Alternative, Applicative, Monad
, MonadPlus, MonadIO, HasRqData, ServerMonad
, WebMonad Response, FilterMonad Response
, Happstack, MonadState States )
class HasSimple m st where
getSimple :: m (Simple st)
putSimple :: (Simple st) -> m ()
instance HasSimple App Int where
getSimple = simpleState <$> get
putSimple input = do
whole <- get
put $ whole {simpleState = input}
simpleQuery :: ( Functor m
, HasSimple m a
, MonadIO m
, Show a
) =>
m a
simpleQuery = do
(Simple a) <- getSimple
return a
simpleUpdate :: ( Functor m
, HasSimple m a
, MonadIO m
, Show a
) =>
a
-> m ()
simpleUpdate a = putSimple (Simple a)
runApp :: States -> App a -> ServerPartT IO a
runApp states (App sp) = do
mapServerPartT (flip evalStateT states) sp
rootDir :: App Response
rootDir = do
intVal <- simpleQuery
let newIntVal :: Int
newIntVal = intVal + 1
simpleUpdate newIntVal
ok $ toResponse $ ("hello number:" ++ (show newIntVal))
main :: IO ()
main = do
simpleHTTP nullConf $ runApp initialStates rootDir
它编译,但每次请求网页时,页面显示相同的数字。再次查看我的代码,我觉得 runApp 中的 evalStateT 是错误的,因为它从不使用更新的状态值。
现在,我正在阅读 mapServerPartT 和 ServerPartT,但这太复杂了。感谢是否有人可以回答标题行:“如何在 Happstack 中携带非酸性价值?”