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)
This is a simple nodejs/express server application which stores the http request body in a global variable and sends the same variable as responsse on a get request.
How to write this code in yesod/haskell. I don't know how to use global/module-scoped variables in haskell/yesod. And, is there any other way to share variables between two functions in haskell?
Using global constants is trivial in Haskell: you just write foo = bla somewhere (preferrably with a signature foo :: FooType). foo can then be used anywhere in your module (or even outside, if you export it).
Global variables OTOH aren't really possible in Haskell, as such. For the most part, that's a good thing because global state tends to lead to lots of bugs. Often when programmers think about global variables, it turns out global constants would be just fine, or otherwise the mutable state should better be re-written as explicit parameters.
Sometimes however you pretty much do need state variables. In Yesod in particular, there's a place where you can store them sort-of globally: the Yesod. That is the data structure that your web application has as its “basement”. For instance, you may have
data YourYesod = YourYesod {
...
, reqStore :: IORef RequestBody -- IORef basically means, it's variable
-- in the imperative sense.
...
}
mkYesod "YourYesod" [parseRoutes| ... |]
The Yesod can be accessed from anywhere in the Handler etc. monads, e.g. in
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
...
At the beginning of the program, the reqStore will need to be initialised, by something like
main :: IO ()
main = do
...
initReqStore = newIORef emptyRequest
...
warp 3000 $ YourYesod ... initReqStore ...
Before doing it this way, think about whether the store variable really needs to be that global. The Yesod is pretty much the most global scope you have for stuff like that; that means also danger of those typical bugs like in procedural languages. If the variable is only used within one handler, you might as well just introduce it locally, like
do
...
store <- newIORef emptyRequest
appPost "/" $ \req res -> do
liftIO $ writeIORef store $ body req
appGet "/" $ \req res -> do
storedReq <- liftIO $ readIORef store
send res storedReq
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With