[Haskell] thread-local variables

Einar Karttunen ekarttun at cs.Helsinki.FI
Sat Aug 5 13:57:46 EDT 2006


On 05.08 14:32, Frederik Eaton wrote:
> > If it is documented maybe it could be done at the level of an
> > implicit parameter?
> 
> Do you think implicit parameters are better than TLS?


Implicit parameters are explicit and the type checker
guards that they are not undefined (and thus are safe
in the presence of callbacks). I haven't used implicit
parameters extensively because I prefer the monadic
approach.

> > I don't consider these very different:
> > 1) use one thread from a pre-allocated pool to do a task
> > 2) fork a new thread to do the task
> > 
> > With TLS they are vastly different.
> 
> If you don't consider them different, then you can start using (2)
> instead of (1).

Performance reasons or access to a shared resources. Also 2) would
mean in many cases making currently local state global which is
not nice.

> Can you give the API for your library? I have a hard time imagining
> how it could not be obvious that a thread pool is being used.

e.g. various

withFooResource :: (Foo -> IO a) -> IO a

can use worker threads.

> > As said before the monadic approach can be quite clean. I haven't used
> > implicit parameters that much, so I won't comment on them.
> 
> Perhaps you can give an example? As I said, a single monad won't
> suffice for me, because different libraries only know about different
> parts of the state. With TLS, one can delimit the scope of parameters
> by making the references to them module-internal, for instance.
> 
> With monads, I imagine that I'll need for each parameter
> 
> (1) a MonadX class, with a liftX member
> (2) a catchX function
> (3) a MonadY instance, for each wrapped monad Y (thus the number of
> such instances will be O(n^2) where n is the number of parameters)

That is usually the wrong approach. Newtype something like
"StateT AppState IO". Use something like:

runWithPart :: (AppState -> c) -> (c -> IO a) -> AppM a

to define nice actions for different parts of the libraries.

Usually this is very easy if one uses combinators and high level
constructs and messier if it is hard to find the right combinators.

If you look at the various web frameworks in Haskell you will notice
that most of them live happily with one monad and don't suffer from
problems because of that.

> With TLS, I need
> 
> (1) a declaration "x = unsafePerformIO $ newIOParam ..."

And don't have any static guarantees that you have done all the proper
initialization calls before you use them.

In the previous example we were using a lot of libraries using hidden
state. How do we guarantee that they have valid values in TLS?
Also if we have two pieces of the same per-thread state that
we wish to use in one thread (e.g. db-connections) then the TLS
approach becomes quite hard.

Here is a naive and dirty implementation. The largest problem is that
TypeRep is not in  Ord. An alternative approach using Dynamic would be
possible, but I like the connection between the key 
and the associated type.

http://www.cs.helsinki.fi/u/ekarttun/haskell/TLS/

Not optimized for performance at all.

- Einar Karttunen



More information about the Haskell mailing list