var express = require('express')
var app = express()
var store = undefined
app.post("/", function(req, res){
store = req.body
})
app.get("/", function(req, res){
res.send(store)
}
app.listen(some_port_num)
这是一个简单的nodejs / express服务器应用程序,它将http请求主体存储在全局变量中,并在get请求中将相同的变量作为response发送。
如何在yesod / haskell中编写此代码。我不知道如何在haskell / yesod中使用全局/模块范围的变量。并且,还有其他方法可以在haskell中的两个函数之间共享变量吗?
答案 0 :(得分:6)
在Haskell中使用全局常量是微不足道的:你只需在某处写foo = bla
(最好用签名foo :: FooType
)。然后可以在模块中的任何位置使用foo
(如果导出它,甚至可以在外部使用)。
全局变量 OTOH在Haskell中确实不可能,因此。在大多数情况下,这是一件好事,因为全局状态往往导致批次的错误。通常当程序员考虑全局变量时,结果表明全局常量会很好,否则最好将可变状态重写为显式参数。
但有时你几乎需要状态变量。特别是在Yesod,您可以在这里存储全局排序: Yesod 。这是您的Web应用程序作为其“基础”的数据结构。例如,你可能有
data YourYesod = YourYesod {
...
, reqStore :: IORef RequestBody -- IORef basically means, it's variable
-- in the imperative sense.
...
}
mkYesod "YourYesod" [parseRoutes| ... |]
可以从Handler
等monad中的任何位置访问Yesod,例如在
getHomeR :: Handler Html
getHomeR = do
...
yourYesod <- getYesod -- gain "access" to the Yesod
storeS <- liftIO $ readIORef (reqStore yourYesod) -- look up the variable state
...
liftIO $ writeIORef (reqStore yourYesod) newStoreS -- write new state
...
在程序开始时,reqStore
需要初始化,例如
main :: IO ()
main = do
...
initReqStore = newIORef emptyRequest
...
warp 3000 $ YourYesod ... initReqStore ...
在这样做之前,请考虑store
变量是否真的需要全局变量。对于像这样的东西,Yesod几乎是全球最大的范围;这也意味着程序语言中的典型错误的危险。如果变量仅在一个处理程序中使用,您也可以在本地引入它,如
do
...
store <- newIORef emptyRequest
appPost "/" $ \req res -> do
liftIO $ writeIORef store $ body req
appGet "/" $ \req res -> do
storedReq <- liftIO $ readIORef store
send res storedReq