Search code examples
haskellvectorstatemutable

How to mutate an STVector?


MVector comes in two flavors, IOVector and STVector. I want to write some functions that use STVector, so that they can be called from pure code despite using the fast mutable-vector algorithms in Data.Vector.Algorithms.

With the help of a related thread, I've gotten partway there: I can stick an immutable Vector into a mutable ST context:

import Control.Monad.ST
import Data.Vector
import Data.Vector.Algorithms.Intro (sort)

x = fromList [1,4,2] :: Vector Int

verboseCopy :: Vector Int
verboseCopy = runST $ do v <- thaw x
                         freeze v

I just need to run sort between the thaw and the freeze.

Perhaps surprisingly, I did not have to import Data.Vector.Mutable, which is where STVector is defined. Maybe I should use a type signature to specify that I want thaw to produce an STVector, but I don't know how: If I change the thaw line to this:

v <- thaw x :: Data.Vector.Mutable.STVector s Int

I get this error:

• Couldn't match expected type ‘MVector
                                  (primitive-0.6.3.0:Control.Monad.Primitive.PrimState (ST s))
                                  Int’
              with actual type ‘Int’
• In the first argument of ‘freeze’, namely ‘v’

Solution

  • You should be fine to write:

    verboseCopy :: Vector Int
    verboseCopy = runST $ do v <- thaw x
                             sort v
                             freeze v
    

    giving:

    > verboseCopy
    [1,2,4]
    >
    

    The sort v performs the sort as a side effect on the mutable vector v, so there's no need to "save" or "capture" the sort result, if that's what you were worried about.

    You don't need to explicitly type v. Haskell will infer it to be a mutable vector and will treat it appropriately as an IOVector or STVector depending on whether you are using it within the IO or ST monad.

    For your information, the reason you're getting the error is that the type you're supplying is for v, but you've applied it to thaw x which has a more complex type. If you write:

    verboseCopy :: Vector Int
    verboseCopy = runST $ do v <- thaw x :: ST s (STVector s Int)
                             sort v
                             freeze v
    

    then it'll type check. However, again, this is unnecessary and won't change the behavior at all. Haskell has already figured out this type for you.