Thanks for your response.
There 's one thing I don't understand however: the countRef function
returns the same MVar all the time.
What 's the reason for that ? I would expect that every time that
function is invoked, it returns a new MVar,
but clearly it does not.
From the documentation of unsafePerformIO
Use {-# NOINLINE foo #-} as a pragma on any function foo that calls
unsafePerformIO. If the call is inlined, the I/O may be performed
more than once.
I try to conclude that writing the Pragma NOINLINE somehow makes
sure that the result of countRef is computed only once! And
subsequent invocations of the function will return the same result.
In a way this makes sense because a function that is invoked twice
with the same arguments "computes" the same result.
But, somehow it is a very nasty hack.
Am I getting it, or am I completly wrong ?
kind regards,
Pieter
On 18-feb-07, at 03:26, Donald Bruce Stewart wrote:
pieter:
Hello,
I'm trying to write a simple module for the haskell web server (hws-
cgi).
And I would like to write a simple module that maintains some kind of
state for a session.
But I'm I write I cannot do this in pure Haskell ? Without adopting
the sources of the Haskell web server ?
I'll examplify to make it more concrete :
The requestHandler function a module has to implement has this
signature.
requestHandler :: ServerState -> ServerRequest -> IO (Maybe
Response)
Let 's assume I have this implementation
requestHandler st _ = return $ Just $ mkRequest
where mkRequest =
okResponse (serverConfig st) mkBody hs True
mkBody = HereItIs " This is a test"
hs = mkHeaders [contentTypeHeader "text/html"]
And I would like the response to include, for example, a number
indicating the number of calls that has been handled by the module.
I would concider using an Mvar but I can't "remember" the mvar
between requests.
Am I right to assume that the interface of the requestHandler method
has to be adapted ? Or that serverstate has to be adopted so that it
can act as a datastore ?
I don't think so.
You could, for example store the count on disk, and read it back
in. Or
you could simulate a disk store by using a mutable variable, hidden in
your module:
module M (requestHandler) where
import Control.Concurrent.MVar
import System.IO.Unsafe
--
-- A threadsafe mutable variable, internal to this module. Rather
-- than use, say, a disk file as storage, we can keep the count
here.
--
countRef :: MVar Int
countRef = unsafePerformIO $ newMVar 0
{-# NOINLINE countRef #-}
----------------------------------------------------------------------
--
-- And a quick example:
type Response = Int
requestHandler :: IO (Maybe Response)
requestHandler = do
n <- modifyMVar countRef $ \c -> return (c+1, c)
print $ "received " ++ show n ++ " requests."
return $ case n of
0 -> Nothing
_ -> Just n
*Main> requestHandler
"received 0 requests."
Nothing
*Main> requestHandler
"received 1 requests."
Just 1
*Main> requestHandler
"received 2 requests."
Just 2
*Main> requestHandler
"received 3 requests."
Just 3
This seems simpler than writing the count to disk. And as long as you
stay in IO, perfectly safe.
In the longer term, you might want to look at state-parameterised
plugins for the HWS. We do this in lambdabot, associating a private
state type with each plugin, which is managed by the main server. The
plugins can then get or set internal state, without resorting to local
mutable variables.
-- Don
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe