在Web.Scotty中使用StateT [英] Use StateT within Web.Scotty
问题描述
我试图制作一个愚蠢的网络服务器,将数据存储为 State
。我正在使用 Web.Scotty
。 我之前用scotty使用过ReaderT来访问配置,但遵循相同的方法在这里不起作用。它会在每个请求中重置状态。
我想在程序启动时设置初始状态,然后在程序的整个生命周期中保持同样的状态。
我该如何做这项工作? (以下每个请求都会创建一个新的状态)
$ $ p $ $ $ c $ {$#$ L $ $ b $ import import Web.Scotty .Trans
导入Control.Monad.State(StateT,evalStateT,lift)
将合格的Control.Monad.State导入为S
import Data.Text.Lazy(Text)
main :: IO()
main = do
let runner = flip evalStateTmessage
scottyT 3000 runner runner routes
routes :: ScottyT Text (StateT Text IO)()
routes = do
$ b $ get/ data$ do
val< - lift S.get
text val
放入/ data /:val$ do
val < - paramval
lift $ S.put val
text val
您看到的行为绝对是预期的行为:
注释请参阅文档中的第三个参数对于 scottyT
:
- > (m响应 - > IO响应)
- 将monadm
运行为IO
,
您可以将状态存储在 StateT $ c外部$ c> monad,以便您可以将其恢复到每个操作的处理程序中。我能想到的最简单的方式就是这样:
main :: IO()
main = do
let s0 =message
let transform = flip evalStateT s0
runner< - restartableStateT s0
scottyT 3000变换跑步者路线
restartableStateT :: s - > IO(StateT s IO a - > IO a)
restartableStateT s0 = do
r < - newIORef s0
return $ \act - > do
s< - readIORef r
(x,s')< - runStateT act s
atomicModifyIORef'r $ const(s',x)
但是这并不能解决两个请求同时发生时应该发生的情况,它只是最后一个赢得胜利。
I'm trying to make a silly webserver that stores data as State
. I'm using Web.Scotty
. I've used ReaderT before with scotty to access config, but following the same approach doesn't work here. It resets the state on every request.
I want to set the initial state when the program starts, then have that same state stick around for the whole life of the program.
How can I make this work? (The following creates a new state every request)
{-# LANGUAGE OverloadedStrings #-}
import Web.Scotty.Trans
import Control.Monad.State (StateT, evalStateT, lift)
import qualified Control.Monad.State as S
import Data.Text.Lazy (Text)
main :: IO ()
main = do
let runner = flip evalStateT "message"
scottyT 3000 runner runner routes
routes :: ScottyT Text (StateT Text IO) ()
routes = do
get "/data" $ do
val <- lift S.get
text val
put "/data/:val" $ do
val <- param "val"
lift $ S.put val
text val
The behaviour you are seeing is definitely the expected one:
note the remark on the third argument in the documentation for scottyT
:
-> (m Response -> IO Response)
-- Run monadm
intoIO
, called at each action.
What you could do is store the state external to the StateT
monad so that you can reinstate it in the handler of every action. The most naïve way I can think of to do that would be something like this:
main :: IO ()
main = do
let s0 = "message"
let transform = flip evalStateT s0
runner <- restartableStateT s0
scottyT 3000 transform runner routes
restartableStateT :: s -> IO (StateT s IO a -> IO a)
restartableStateT s0 = do
r <- newIORef s0
return $ \act -> do
s <- readIORef r
(x, s') <- runStateT act s
atomicModifyIORef' r $ const (s', x)
but this doesn't really address what should happen if two requests are coming in concurrently, it's just "last one to finish wins".
这篇关于在Web.Scotty中使用StateT的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!