Simon Marlow in his book "Parallel and Concurrent Programming in Haskell" writes:
The insert operation hadthis line:
putMVar m (Map.insert name number book)
This places in the MVar the unevaluated expression
Map.insert name number book
. If we were to do many insert operations consecutively, the MVar would build up a large chain of unevaluated expressions. To get brief locking and no space leaks, we need to use a trick:let book' = Map.insert name number book putMVar m book' seq book' (return ())
With this sequence, we’re storing an unevaluated expression in the MVar, but it is evaluated immediately after the putMVar.
I don't get it. seq a b
operation evaluates a
in weak head normal form. So there will be unevaluated expression. As I can see only the Map constructor will be evaluated and all of it contents will be unevaluated.
As I can see only the
Map
constructor will be evaluated and all of it contents will be unevaluated.
Internally, the Map
type is implemented using a strict tree. Either the whole tree spine gets evaluated, or none of it. Here's a snippet from the library code:
data Map k a = Bin {-# UNPACK #-} !Size !k a !(Map k a) !(Map k a)
| Tip
The strictness annotations (!
) prevent unevaluated values to be stored as subtrees. So, if we evaluate a Map k a
value to weak head normal form, we actually fully evaluate the tree spine.