Search code examples
haskellvectorprintingmutable

Haskell how to print mutable vector


import           Control.Monad.IO.Class  (liftIO)
import           Control.Monad.Primitive
import qualified Data.Vector             as V
import qualified Data.Vector.Mutable     as MV

fromList :: [a] -> IO (MV.IOVector a)
fromList = V.thaw . V.fromList

printMV :: PrimMonad m => MV.MVector (PrimState m) a -> m ()
printMV = liftIO . print . V.freeze

I want to print MVector (surprised that there isn't a show instance). So I have to freez it first to Vector. And then I got type errors:

Algo/QuickSort.hs:12:11: error: …
    • Couldn't match type ‘PrimState m’ with ‘PrimState m0’
      Expected type: MV.MVector (PrimState m) a -> m ()
        Actual type: MV.MVector (PrimState m0) a -> m ()
      NB: ‘PrimState’ is a non-injective type family
      The type variable ‘m0’ is ambiguous
    • In the expression: liftIO . print . V.freeze
      In an equation for ‘printMV’: printMV = liftIO . print . V.freeze
    • Relevant bindings include
        printMV :: MV.MVector (PrimState m) a -> m ()
          (bound at /home/skell/btree/Algo/QuickSort.hs:12:1)
   |
Compilation failed.

I've also tried the IOVector

printMV :: MV.IOVector a -> IO ()
printMV = liftIO . print . V.freeze

This time the error is different:

Algo/QuickSort.hs:12:28: error: …
    • Couldn't match type ‘PrimState m0’ with ‘RealWorld’
      Expected type: MV.IOVector a -> m0 (V.Vector a)
        Actual type: MV.MVector (PrimState m0) a -> m0 (V.Vector a)
      The type variable ‘m0’ is ambiguous
    • In the second argument of ‘(.)’, namely ‘V.freeze’
      In the second argument of ‘(.)’, namely ‘print . V.freeze’
      In the expression: liftIO . print . V.freeze
   |
Compilation failed.

Solution

  • there are a couple of things going on - first one solution:

    printMV :: MonadIO m => Show a => PrimMonad m => MV.MVector (PrimState m) a -> m ()
    printMV v = do
        fv <- V.freeze v
        liftIO $ print fv
    

    So the issues:

    • freeze is an m-action itself so it needs to be bound
    • liftIO needs an MonadIO instance
    • in order for Vector a to be Show - a has to be in that class too

    your second version is similar:

    printMV2 :: Show a => MV.IOVector a -> IO ()
    printMV2 v = V.freeze v >>= print
    
    • need the Show instance for a
    • need to >>= the result of V.freeze (same as above - do does this implicitly)
    • here there is no need for liftIO as you are already in it