本文介绍了在Web.Scotty中使用StateT的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 我试图制作一个愚蠢的网络服务器,将数据存储为 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 lift $ S.put val text val 解决方案您看到的行为绝对是预期的行为:注释请参阅文档中的第三个参数对于 scottyT : - > (m响应 - > IO响应) - 将monad m 运行为 IO , 您可以将状态存储在 StateT 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 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.Transimport Control.Monad.State (StateT, evalStateT, lift)import qualified Control.Monad.State as Simport Data.Text.Lazy (Text)main :: IO ()main = do let runner = flip evalStateT "message" scottyT 3000 runner runner routesroutes :: 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 monad m into IO, 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 routesrestartableStateT :: 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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
10-30 17:59