Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
878 views
in Technique[技术] by (71.8m points)

haskell - How does the ST monad work?

I understand that the ST monad is something like a little brother of IO, which in turn is the state monad with added RealWorld magic. I can picture states and I can picture that RealWorld is somehow put into IO, but every time I write a type signature of ST the s of the ST monad confuses me.

Take, for example, ST s (STArray s a b). How does the s work there? Is it just used to build up some artificial data dependency between computations without being able to be referenced like states in the state monad (due to the forall)?

I'm just throwing out ideas and would really appreciate someone more knowledgeable than I to explain it to me.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The s keeps objects inside the ST monad from leaking to the outside of the ST monad.

-- This is an error... but let's pretend for a moment...
let a = runST $ newSTRef (15 :: Int)
    b = runST $ writeSTRef a 20
    c = runST $ readSTRef a
in b `seq` c

Okay, this is a type error (which is a good thing! we don't want STRef to leak outside the original computation!). It's a type error because of the extra s. Remember that runST has the signature:

runST :: (forall s . ST s a) -> a

This means that the s on the computation that you're running has to have no constraints on it. So when you try to evaluate a:

a = runST (newSTRef (15 :: Int) :: forall s. ST s (STRef s Int))

The result would have type STRef s Int, which is wrong since the s has "escaped" outside of the forall in runST. Type variables always have to appear on the inside of a forall, and Haskell allows implicit forall quantifiers everywhere. There's simply no rule that allows you to to meaningfully figure out the return type of a.

Another example with forall: To clearly show why you can't allow things to escape a forall, here is a simpler example:

f :: (forall a. [a] -> b) -> Bool -> b
f g flag =
  if flag
  then g "abcd"
  else g [1,2]

> :t f length
f length :: Bool -> Int

> :t f id
-- error --

Of course f id is an error, since it would return either a list of Char or a list of Int depending on whether the boolean is true or false. It's simply wrong, just like the example with ST.

On the other hand, if you didn't have the s type parameter then everything would type check just fine, even though the code is obviously pretty bogus.

How ST actually works: Implementation-wise, the ST monad is actually the same as the IO monad but with a slightly different interface. When you use the ST monad you actually get unsafePerformIO or the equivalent, behind the scenes. The reason you can do this safely is because of the type signature of all ST-related functions, especially the part with the forall.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...