1
votes
  test :: VM.MVector s Int -> Int
  test x = runST $ do
    a <- return x
    VM.read a 0 -- Type error

I am trying to figure out how to not put everything inside a ST monad into a single function. If I tried to modify x or return a value from it, the compiler would complain about the state part of the mutable vector not matching up.

Would operating on passed mutable vectors be possible in Haskell or do I have to freeze them into the immutable counterparts before doing anything on them?

Edit:

Here is the actual error.

Couldn't match type `s1' with `s'
  `s1' is a rigid type variable bound by
       a type expected by the context: ST s1 Int at rjb.hs:17:12
  `s' is a rigid type variable bound by
      the type signature for test :: VM.MVector s Int -> Int
      at rjb.hs:16:11
Expected type: VM.MVector
                 (Control.Monad.Primitive.PrimState (ST s1)) Int
  Actual type: VM.MVector s Int
Relevant bindings include
  a :: VM.MVector s Int (bound at rjb.hs:18:5)
  x :: VM.MVector s Int (bound at rjb.hs:17:8)
  test :: VM.MVector s Int -> Int (bound at rjb.hs:17:3)
In the first argument of `VM.read', namely `a'
In a stmt of a 'do' block: VM.read a 0

Edit: The following passes type checking.

  test :: VM.MVector (Control.Monad.Primitive.PrimState IO) Int -> IO (Int)
  test x = VM.read x 0

I am guessing that I would be able to mutate the x vector as well. So...

1
can you please add the actual error? - Random Dev
a <- return x is redundant. That just gives you x again. - melpomene
@Carsten Added the error. - Marko Grdinic
It would help if you included your imports. - ErikR
If you want to mutate a monadic vector, you have to return a monadic value. That's the whole point of monads: side effects must appear in the type. A function of type VM.MVector s Int -> Int is necessarily a constant function. - chi

1 Answers

7
votes

You probably need some example. Here's a basic commented one, but I'm sure you'll find others in the net if you google a bit.

import Control.Monad.ST
import qualified Data.Vector.Mutable as VM

-- This returns a reference to a vector, wrapped in the ST s monad.
test :: ST s (VM.MVector s Int)
test = do
  v <- VM.new 10       -- create vector
  VM.write v 3 2000    -- modify it
  VM.write v 4 3000
  x <- VM.read v 3     -- access it
  VM.write v 4 (x+1)   
  return v             -- return it

-- This instead returns a (wrapped) Int
test2 :: ST s Int
test2 = do
  v <- test            -- call test, which performs the allocation
  VM.read v 4          -- return v[4]

-- This returns a plain pure Int value    
test3 :: Int
test3 = runST test2

Note that runST x can only be used when the type of x is the polytype ST s T where T does NOT involve the type variables s. This is how the ST monad achieves referential transparency.

In more simple terms, this means that any "pointer" to allocated memory must never be returned by runST. When runST returns, every allocation of mutable things can be freed. Hence, a typical ST s computation performs runST only at the very end, when it's ready to throw away all the mutable data and keep an immutable portion of it. In the example above, the immutable portion was the 4th element (counting from 0, as usual), which is an immutable Int.

If you are not familiar with ST s, I'd recommend you forget about vectors for the moment, and do some practice with STRef s Int (references to Int) and ST. Any ST tutorial would suffice.