2014-12-16 10 views
8

데이터를 저장하는 어리석은 웹 서버를 State으로 만들려고합니다. Web.Scotty을 사용하고 있습니다. I've used ReaderT before with scotty to access config이지만 동일한 접근법을 따르는 것은 여기서 작동하지 않습니다. 요청이있을 때마다 상태를 재설정합니다.Web.Scotty 내에서 StateT 사용

프로그램이 시작될 때 초기 상태를 설정하고 프로그램의 전체 수명 동안 동일한 상태를 유지하려고합니다.

어떻게하면됩니까? 참고 documentation for scottyT에서 세 번째 인수의 말 :

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

완전히 기능하지 않는 언어 (apache, tomcat 등)로 작성된 웹 서버조차도 일반적으로 메모리에 공유 상태를 저장하지 않습니다 .... 잠금, 상태 종료시의 저장, 데이터를 사용자에게 매핑하는 것 등이 있습니다. 이것은 데이터베이스가 존재하는 이유입니다. 내 추측은 당신이 Scotty에서하고 싶은 일을 할 수 없다는 것이며, Scotty 제작자는 그것을 구현하고 싶지 않을 것입니다. 내 추측). – jamshidh

+0

그건 의미가 있습니다. 내가 이것을하고있는 유일한 이유는 node.js에서 오는 일부 사람들이 haskell을 가르치는 것이고, 우리가 데이터베이스를 던지기 전에 쉬운 첫 단계와 같이 보일 것이다. –

답변

6

당신이보고있는 행동을 예상 하나를 확실히 (다음은 새로운 상태마다 요청을 만듭니다)

-> (m Response -> IO Response)을 - 실행을 모나드 m을 각 동작마다 호출되는 IO으로 호출합니다.

당신이 할 수있는 일은 StateT 모나드의 외부에 상태를 저장하여 모든 동작의 처리기에서 복원 할 수 있도록하는 것입니다. 내가 생각할 수있는 가장 순진 방법은 즉,이 같은 것 할 :

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) 

하지만 정말 두 개의 요청이 동시에 들어오는 경우 어떻게해야하는지 언급하지 않는, 그것은 승리를 완료 그냥 "마지막 하나 ".

+0

예를 들어 이 정확한 시나리오에 대한 scotty docs https://github.com/scotty-web/scotty/blob/master/examples/globalstate.hs – fommil