Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Data.Vector.Mutable read() return in the monad since its an immutable operation?

Tags:

haskell

vector

Looking here http://hackage.haskell.org/package/vector-0.12.0.3/docs/Data-Vector-Mutable.html One can see that the type of read is:

read :: PrimMonad m => MVector (PrimState m) a -> Int -> m a

Since read operation does not modify the vector, my main question is why is it not:

read :: PrimMonad m => MVector (PrimState m) a -> Int -> a

The length of a mutable vector is also doing something immutable on a vector, and its type is MVector s a -> Int which looks normal. It is not PrimMonad m => MVector (PrimState m) a -> m Int. So why was this difference of design choice made between read and length since they are both immutable operations on a vector?

Now that I think about it, could it be somehow that the cell returned by read is a reference to the cell inside the vector and not a copy of its data? If so how can I nicely and cheaply get immutable access to the n-th element in a mutable vector? I'm learning haskell and not too sure about details.

Thanks,

like image 784
jam Avatar asked Oct 10 '19 20:10

jam


2 Answers

Assume

read :: MVector s a -> Int -> a

which means read is pure. Consider

main :: IO ()
main = do
  cell <- replicate 1 'a' -- cell = ['a']
  print $ read cell 1 -- we want to print 'a'
  write cell 1 'z' -- cell = ['z']
  print $ read cell 1 -- we want to print 'z'

Something's gone wrong: I wrote read cell 1 twice, passing the same cell and 1 arguments, so the two calls should return the same value. That's what it means for read to be pure. The above should be equal to

main :: IO ()
main = do
  cell <- replicate 1 'a' -- cell = ['a']
  let contents = read cell 1 -- contents = 'a'
  print contents -- prints 'a'
  write cell 1 'z' -- cell = ['z']; definitely should not affect contents
  print contents -- prints 'a'

But we don't want that: we want read to return different things even when we pass the same arguments, taking into account any writes that might have happened in between. Therefore, read must be a monadic action.

This is different from length. A vector's length never changes, even if the vector is mutable; the length fixed at creation. Therefore, length is a pure function; it doesn't matter what monadic actions you've performed between creating a vector and querying its length; it will always be the same.

like image 57
HTNW Avatar answered Nov 04 '22 04:11

HTNW


Consider

foo = do
   ...
   x1 <- read vector 3
   write vector 3 something
   x2 <- read vector 3
   return (x1 == x2)

If read becomes non monadic, we can instead write this

foo = do
   ...
   let x1 = read vector 3
   write vector 3 something
   let x2 = read vector 3
   return (x1 == x2)

which is equivalent, by referential transparency, to

foo = do
   ...
   let x1 = read vector 3
   write vector 3 something
   let x2 = x1
   return (x1 == x2)

Here, we have an issue: the last snippet always returns True at the end, while the first one does not. So the two snippets are not really equivalent.

Reading must be considered an effect, not because it is observable from outside (it is not), but because it produces a different result depending on the state of the vector, which is effected by writes.

like image 4
chi Avatar answered Nov 04 '22 06:11

chi