Jones and Launchbury described in their paper "Lazy Functional State Threads" the ST monad. To ensure that mutable variables can't be used outside the context (or "thread") they have been created in, they use special types, including one of higher rank. Here four important examples:
newVar :: ∀ s a. a -> ST s (MutVar s a)
readVar :: ∀ s a. MutVar s a -> ST s a
writeVar :: ∀ s a. MutVar s a -> a -> ST s ()
runST :: ∀ a. (∀ s. ST s a) -> a
In order to get the idea behind that construction I read the first two sections of the paper. The following explanation seems to be central:
Now, what we really want to say is that
newST
should only be applied to a state transformer which usesnewVar
to create any references which are used in that thread. To put it another way, the argument ofrunST
should not make any assumptions about what has already been allocated in the initial state. That is,runST
should work regardless of what initial state it is given. So the type ofrunST
should be:runST :: ∀ a. (∀ s. ST s a) -> a
The explanation is fine, but I wonder how it maps to the final definition of the required type. My
problem is that I don't know how to interpret the type variable s
. As stated in Section 1, a state
is essentially a mapping from variables to values. But what is a state type s
? In what can a state
type s
differ from another one t
? For me there are two possibilities:
(1) The type s
can be seen as the concrete type for a mapping of variables such as lists, arrays
and sequences can be seen as concrete types for sequential collections. (I intentionally avoid here
the words "class" and "implementation" as there is no class restriction on the type of s
.)
(2) The type s
can be seen as a concrete value, i.e. a concrete state, i.e. a concrete mapping of
variables.
Interpretation (2) maps nicely to Jones' and Launchbury's explanation of the type of runST
. The
all-quantification expresses the independence of the actual state (which is fully described by the
state type). The flaw in this interpretation is however the type of writeVar
. As it clearly
modifies the state, it should be of type ∀ s a. MutVar s a -> a -> ST t ()
. So this
interpretation must be false.
Interpretation (1) however is not really better because it doesn't map to Jones' and Launchbury's
explanation. The type ∀ s a. ST s a -> a
for runST
would be fine. The important thing is that
there mustn't be any assumption about the concrete value of the state (of type s
) which is given
to the function. Hence the all-quantification shouldn't be over the state type but (instead) over
the concrete value of the state. The type system must express that the result of the stateful
action, which is given to runST
, is independent of the state (but not independent of its type).
Hence both of my interpretations are false. I really tried to understand everything of this type construction. Is there someone who can explain that to me?
PS. I have already read the thread [How does the ST monad work? but it didn't help me. When I do the unification algorithm with my hand I see, that the mechanism works and how it works (by using the limits of scopes) but I really want to understand it – not just see that it works.