Happstack クラッシュコースを読みました。私の Web サーバーには、透過的に複数の AcidState ハンドルを渡すセクションで説明したほぼ正確な方法があります。
私が抱えている問題は、非酸性の値がありますが、Happstack アプリケーション内でアクセスしたいということです。具体的に言えば、 push-notify-general ライブラリの「PushManager」、
私が欲しかったのは:
data Acid = Acid
{ acidCountState :: AcidState CountState
, acidGreetingState :: AcidState GreetingState
, acidPushManager :: AcidState PushManager
}
1) PushManager は非常に多くのデータ型を内部で使用しており、$(deriveSafeCopy ...) を呼び出して基になるデータ型の SafeCopy と互換性を持たせることは現実的ではなく、堅牢ではないため、これを機能させることができませんでした。2) PushManager には単純な値だけでなく、SafeCopy と互換性のある機能も含まれています。
私が試したもう1つのことは、AcidStateだけでなく非AcidStateデータも運ぶ「Acid」データ宣言です。runApp の定義を見てみると、「Acid」は単に Read に使われているだけなので、State モナドで書き換えれば解決できるのではないかと思いました。-しかし、それはそれほど単純ではないことがわかりました。私の暫定的なコードは次のとおりです。
{-# 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
コンパイルしましたが、Webページがリクエストされるたびに、ページには同じ番号が表示されます。コードをもう一度見てみると、runApp の evalStateT が間違っていると感じました。これは、更新された状態値を使用しないためです。
今、mapServerPartT と ServerPartT を読んでいますが、それは複雑すぎます。誰かがタイトル行に答えることができれば感謝します:「Happstack で非酸性の価値を運ぶ方法は?」