I made a function in haskell that is supposed to take a list along with the size of the list; and it is supposed to create a Data.Vector.Mutable.MVector with the given size, fill the vector with the contents of the list and return this vector.
TL;DR
This is the function:
vecFromList lst sz = MV.new sz >>= (\vec -> fillV (zip [0..sz - 1] lst) vec) where
fillV [] vec = vec
fillV ((i, v):xs) vec = MV.write vec i v >> fillV xs vec
Most of it I wrote without really trying to understand what they do (the last line) and as a consequence, I am not able to come up with a suitable type signature. However, the compiler stepped in to save the day with this:
Compiler generated type signature
vecFromList
:: (PrimMonad (MVector t), PrimState (MVector t) ~ t) =>
[b] -> Int -> MVector t b
Did I hear someone say Wat? Oh that was just me, anyways... Before I tried compiling it, this is the type signature I thought should work:
The one I thought should work
vecFromList :: PrimMonad m => [t] -> Int -> MV.MVector (PrimState m) t
It should be obvious by this point that this somewhat simplistic looking type signature which seems to look exactly like what I want the function to do, does in fact not work. To come up with the type signature, I was using the type signatures of some of the other functions in the vector module that I thought were similar to it, like this one for example:
Data.Vector.Mutable.read
:: PrimMonad m => MVector (PrimState m) a -> Int -> m a
Now, I'm still relatively new to haskell so I am still trying to get used to the symbols and signs used in the language and especially come close to understanding why what appears to be simple tasks have to become such convoluted things due to Monands. For example, what is the purpose of MVector
having this kind MVector :: * -> * -> *:
??
You're almost there. You're expected type signature is correct except the resulting MVector
needs to be in the monad m
:
vecFromList :: PrimMonad m => [t] -> Int -> m (MV.MVector (PrimState m) t)
The fillV
function should have type
fillV :: [(Int, t)]
-> MV.MVector (PrimState m) t -> m (MV.MVector (PrimState m) t)
but you're []
case gives the vector without return
ing it to the m
type. Here's a working version:
vecFromList :: PrimMonad m => [t] -> Int -> m (MV.MVector (PrimState m) t)
vecFromList lst sz = MV.new sz >>= (\vec -> fillV (zip [0..sz - 1] lst) vec) where
fillV [] vec = return vec
fillV ((i, v):xs) vec = MV.write vec i v >> fillV xs vec
and a working example:
> V.create $ vecFromList [1,2,3] 3
fromList [1,2,3]
Notice that you don't actually modify vec
in your fillV
function, you only reference it, you could use the for_
function from Data.Foldable
instead of explicitly writing a loop. I normally write mutable vector code in do
blocks because it makes things clearer for me:
vecFromList2 :: PrimMonad m => [t] -> Int -> m (MV.MVector (PrimState m) t)
vecFromList2 l n = do
v <- MV.new n
for_ (zip [0..n - 1] l) $ \(i,a) -> MV.write v i a
return v
Unfortunately working with mutable vectors in Haskell can get tricky and it takes practice. Using TypedHoles and PartialTypeSignatures can help.
The Reason MVector
has the PrimState m
it so it can work with ST
or IO
. You can find an explanation of it here .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.