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,
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 write
s 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.
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.
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