haskell – 在Web.Scotty中使用StateT

我正在尝试制作一个将数据存储为状态的愚蠢的网络服务器.我正在使用 Web.Scotty. I’ve used ReaderT before with scotty to access config,但遵循相同的方法在这里不起作用.它会根据每个请求重置状态.

我想在程序启动时设置初始状态,然后在程序的整个生命周期中保持相同的状态.

我怎样才能做到这一点? (以下为每个请求创建一个新状态)

{-# 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

解决方法

您所看到的行为绝对是预期的行为:
注意 documentation for scottyT中第三个参数的注释:

-> (m Response -> IO Response) — Run monad m into IO,called at each action.

您可以做的是将状态存储在StateT monad外部,以便您可以在每个操作的处理程序中恢复它.我能想到的最天真的方式是这样的:

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)

但这并没有真正解决如果两个请求同时进入会发生什么,它只是“最后一个完成胜利”.

相关文章

Mip是什么意思以及作用有哪些
怎么测试Mip页面运行情况
MIP安装的具体步骤有哪些
HTML添加超链接、锚点的方法及作用详解(附视频)
MIP的规则有哪些
Mip轮播图组件中的重要属性讲解