【发布时间】:2014-10-07 11:30:32
【问题描述】:
我读过 Happstack 速成课程。我的网络服务器几乎与Passing multiple AcidState handles around transparently 部分中描述的完全相同
我的问题是,我有非酸性的值,但想在 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 中携带非酸性价值?”
【问题讨论】: