7

I'm trying to get more familiar with Haskell by developing web-app-ish services.

Say I'm developing a web-server and I want to keep persistent state between requests; a counter, for instance. What is the Haskell way of doing things?

I came across this discussion on my Google search. The proposed solution looks like a good example of what not to do.

One idea I had was having the request handler take in an MVar:

requestHandler :: MVar State -> IO (Maybe Response)

When registering the handler, it could be curried with an MVar created in main.

There must be a better way. I can't help but think I'm approaching this problem in a non-functional way.

Thanks!

David
  • 2,533
  • 2
  • 18
  • 16
  • Why try to carry persistent state on the server itself? Seems to me Haskell would match much better with a RESTful design. – Kenogu Labz Jan 25 '13 at 19:47
  • 1
    What's "non-functional" about that approach? You have some state you need to share, so you wrap it up and pass around the reference. Seems pretty straightforward to me. – sclv Jan 25 '13 at 19:57
  • sclv: I'm wondering if there was more of a FRP approach. – David Jan 25 '13 at 21:07
  • 1
    You say that you want a functional solution, but I suspect that you actually want a [compositional solution](http://www.haskellforall.com/2012/08/the-category-design-pattern.html). – Gabriella Gonzalez Jan 26 '13 at 03:44
  • Don't know if it is helpful but this is a example how I do it, https://github.com/gertcuykens/haskell-design let me know if it needs explanation – Gert Cuykens Jan 26 '13 at 18:18

2 Answers2

4

You probably want acid-state, which gives you that exactly: persistent state for Haskell data types. The documentation I linked even starts out with a request counter, just like you asked for.

Note that MVars are not persistent; the counter would get reset when the server is restarted. If that's actually the behavior you want I suggest you use a TVar instead; that way you can update the counter atomically without locks or the risk of deadlocks that go with them.

Dag
  • 682
  • 5
  • 10
1

If you like persistence and TVars, you can use DBRefs, that have the same semantics and the same usage patterns as TVars. You must define a unique key for the state and you have automatic file persistence. For database persistence it is necessary to define an IResource instance.

The state will have a unique counter for each session:

import Data.Map as M
import Data.TCache
import Data.TCache.DefaultPersistence

type Counter= Int
type SessionId :: String
data State= State SessionId Counter deriving (Read, Show, Typeable)

instance Indexable State where
        key (State k _)= k 

requestHandler :: Request -> DBRef State -> IO (Maybe Response)
agocorona
  • 166
  • 1
  • 5