如何在Spock中使用持久状态单子



我刚开始使用haskell,我在使用基本的"echo" REST服务器时遇到了问题。

Spock看起来像是REST服务器的一个很好的起点,我认为我得到了State monad的基础知识,但我在理解如何将runState放在Spock代码周围时遇到了问题。

这是我目前得到的代码。

{-# LANGUAGE OverloadedStrings #-}
module Main where
import Data.Monoid
import Web.Spock.Safe
import qualified Control.Monad.State as S
storeData :: String -> S.State String String
storeData val = do S.put val
                   return val
getData :: S.State String String
getData = do val <- S.get
             return val
main :: IO ()
main =
    runSpock 11350 $ spockT id $
    do get "store" $
           text "Would be a call to getData"

好了,这里是restartableStateT hack的一个版本,作为你的例子:

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE Rank2Types #-}
module Main where
import Data.Monoid
import Data.String (fromString)
import Web.Spock.Safe
import qualified Control.Monad.State as S
import Data.IORef
storeData :: (Monad m) => String -> S.StateT String m String
storeData val = do S.put val
                   return val
getData :: (Monad m) => S.StateT String m String
getData = do val <- S.get
             return val
newtype RunStateT s m = RunStateT{ runStateT :: forall a. S.StateT s m a -> m a }
restartableStateT :: s -> IO (RunStateT s IO)
restartableStateT s0 = do
    r <- newIORef s0
    return $ RunStateT $ act -> do
        s <- readIORef r
        (x, s') <- S.runStateT act s
        atomicModifyIORef' r $ const (s', x)
main :: IO ()
main = do
    runner <- restartableStateT "initial state"
    runSpock 11350 $ spockT (runStateT runner) $ do
        get "store" $ do
            cmd <- param "value"
            case cmd of
                Nothing -> do
                    old <- S.lift getData
                    text $ fromString old
                Just new -> do
                    S.lift $ storeData new
                    text "Stored."

就像另一个答案一样,这一个创建一个全局IORef来存储"状态"。然后,传递给spockTrunner能够通过从IORef获取状态,运行计算并将结果状态放回IORef来运行任何StateT String IO计算。

我想从另一个答案中重申,这不一定是一个好主意,因为它没有并发的故事。我想这可以通过使用STM来掩盖,但是……我觉得你应该用数据库

相关内容

  • 没有找到相关文章

最新更新