为什么Data.Vector.Mutable read()由于其不可变的操作而在monad中返回?

J. *_* M. 5 haskell vector

在这里查看http://hackage.haskell.org/package/vector-0.12.0.3/docs/Data-Vector-Mutable.html 可以看到读取类型为:

read :: PrimMonad m => MVector (PrimState m) a -> Int -> m a
Run Code Online (Sandbox Code Playgroud)

由于读取操作不会修改向量,所以我的主要问题是为什么不这样做:

read :: PrimMonad m => MVector (PrimState m) a -> Int -> a
Run Code Online (Sandbox Code Playgroud)

可变向量的长度在向量上也做不可变的事情,其类型 MVector s a -> Int看起来很正常。不是PrimMonad m => MVector (PrimState m) a -> m Int。那么,为什么在读取和长度之间做出设计选择上的差异,因为它们都是向量上的不变操作?

现在我考虑一下,以某种方式读取返回的单元格是对向量内部单元格的引用,而不是其数据的副本吗?如果是这样,我怎么能以可变的向量很好且廉价地获得对第n个元素的不变访问?我正在学习haskell,但不太了解细节。

谢谢,

HTN*_*TNW 9

假设

read :: MVector s a -> Int -> a
Run Code Online (Sandbox Code Playgroud)

这意味着read是纯粹的。考虑

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'
Run Code Online (Sandbox Code Playgroud)

有什么地方出了问题:我写了read cell 1两次,传递相同 cell1参数,所以两个调用应该返回相同的值。这就是read纯粹的意思。以上应等于

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'
Run Code Online (Sandbox Code Playgroud)

但是我们不希望这样:read即使在传递相同的参数时,我们也想返回不同的东西,要考虑到write它们之间可能发生的任何变化。因此,read必须采取单行动。

这与有所不同length。即使向量是可变的,向量的长度也不会改变。在创建时固定的长度。因此,length 一个纯函数;在创建矢量和查询其长度之间执行了什么单调操作都无关紧要;它将永远是相同的。


chi*_*chi 5

考虑

foo = do
   ...
   x1 <- read vector 3
   write vector 3 something
   x2 <- read vector 3
   return (x1 == x2)
Run Code Online (Sandbox Code Playgroud)

如果read变成非单子,我们可以这样写

foo = do
   ...
   let x1 = read vector 3
   write vector 3 something
   let x2 = read vector 3
   return (x1 == x2)
Run Code Online (Sandbox Code Playgroud)

通过引用透明度,这相当于

foo = do
   ...
   let x1 = read vector 3
   write vector 3 something
   let x2 = x1
   return (x1 == x2)
Run Code Online (Sandbox Code Playgroud)

在这里,我们有一个问题:最后一个片段总是True在最后返回,而第一个片段则不会。所以这两个片段并不真正等同。

读取必须被视为一种效果,不是因为它可以从外部观察到(事实并非如此),而是因为它根据受写入影响的向量状态产生不同的结果。