import           Control.Monad.ST
import           Data.STRef
import qualified Data.Vector.Unboxed         as V
import qualified Data.Vector.Unboxed.Mutable as MV
-- what the heck is that s?
new0 :: (MV.Unbox a, Num a) => ST s (MV.STVector s a)
new0 = do
  v <- MV.new 10
  MV.write v 1 10
  MV.write v 2 10
  return v
new1 :: (MV.Unbox a) => IO (MV.IOVector a)
new1 = MV.new 10
new2 :: (MV.Unbox a, Num a) => IO (MV.STVector RealWorld a)
new2 = do
  v <- MV.new 10
  MV.write v 1 10
  return v
I'm implementing the QuickSort algorithm and I choose Data.Vector.Unboxed.Mutable
I'm completely lost regarding two issues:
Monad: IO or ST
ST. Could anyone show me how to print new0 ?Solutions:
I got some inspirations from this example code
For a good understanding of ST monad, check the original paper: Lazy Functional State Threads
Here's a code snippet showing how to use mutable vectors for quicksort:
import           Control.Monad.Primitive
import           Control.Monad.ST            (runST)
import           Prelude                     hiding (read)
import           Data.List                   (partition)
import qualified Data.Vector.Unboxed         as V
import qualified Data.Vector.Unboxed.Mutable as M
partitionV :: (PrimMonad m, Ord a, V.Unbox a) 
           => M.MVector (PrimState m) a -> Int -> Int -> m Int
partitionV v p r = do
  let i = p
  x <- M.unsafeRead v r
  go i p x
  where
    go i j x | j < r = do
               jv <- M.unsafeRead v j
               if jv < x
                 then M.unsafeSwap v i j >> go (i+1) (j+1) x
                 else go i (j+1) x
    go i _ _ = do
      M.unsafeSwap v i r
      return i
quickSortV :: (PrimMonad m, Ord a, V.Unbox a) 
           => M.MVector (PrimState m) a -> m ()
quickSortV v | M.length v < 2 = return ()
quickSortV v = do
  i <- partitionV v 0 (M.length v - 1)
  quickSortV (M.unsafeSlice 0 i v)
  quickSortV (M.unsafeSlice (i + 1) (M.length v - 1 - i) v)
    -- note the difference between for loop and recursive call
test l = runST $ do
  mv <- V.thaw l
  quickSortV mv
  V.freeze mv
quickSort :: (Ord a) => [a] -> [a]
quickSort []       = []
quickSort (x : xs) =
    let (lt, gt) = partition (<= x) xs
    in  quickSort lt ++ [x] ++ quickSort gt
                The ST monad is for when you want to take some immutable data, make it temporarily mutable, do something with it, and make it immutable again. In particular, there is no way to return a mutable result from the ST monad (by design).
In particular, STVector is mutable, so it can never leave the ST monad. So there is no way to "print out" new0. You would have to convert it to something immutable to return it out of the ST monad.
If you're wanting to mutate something, print it out, mutate it a bit more, print it out, etc., you probably want the IO monad. The ST monad is for making something temporarily mutable, to eventually produce an ordinary immeduate result.
Regarding the s type variable: It's a slight hack that enforces the property that mutable data cannot leave ST. The runST function requires an action that works for every possible choice of s. This means it's impossible to return anything that contains s. Since all the mutable stuff has s in its type signature, this enforces our guarantee.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With