繁体   English   中英

Data.Vector.Mutable 字段无法正确写入/设置? : Haskell

[英]Data.Vector.Mutable field can not be written/set properly? : Haskell

几天来我一直在努力构建一个data结构,该结构具有Data.Vector.Mutable的可变值字段

我确认Data.Vector.Mutable本身的行为符合我的预期; 但是,一旦将其包含在结构中,就会以某种方式停止与我的期望相反的工作。

下面是一个演示代码,它只包含newValgetValsetVal目标结构的可变字段值。

newIO是类型为newIO:: a -> A a的数据结构的构造函数。

module Main where
import Control.Monad.Primitive (PrimMonad (PrimState))
import qualified Data.Vector.Mutable as M 
------------------------------------ 
data A a = A
  { ioVal :: IO (M.MVector (PrimState IO) a)
  }

newIO :: a -> A a
newIO = \a -> A (newVal a)
------------------------------
newVal :: a -> IO (M.MVector (PrimState IO) a)
newVal = \a -> do
  val <- M.new 1
  M.write val 0 a
  return val

getVal :: A a -> IO a
getVal = \aA -> do
  val <- ioVal aA
  M.read val 0

setVal :: a -> A a -> IO ()
setVal = \a -> \aA -> do
  val <- ioVal aA
  M.write val 0 a
------------------------------
main :: IO ()
main = do
  let ioA = newIO (5 :: Int)
  (getVal ioA) >>= print -- 5
  setVal 10 ioA
  (getVal ioA) >>= print -- 5 ?? expected 10

因此,在这里,为了确认结构的set/get的基本行为,我尝试创建、读取、(重新)写入和(重新)读取字段的可变值; 然而,它并没有像预期那样工作。

代码有什么问题? 请指教。

Haskell 的一个主要属性是引用透明性:我们总是可以用定义的实体替换定义的实体。 现在考虑发布的代码:

main :: IO ()
main = do
  let ioA = newIO (5 :: Int)
  (getVal ioA) >>= print -- 5
  setVal 10 ioA
  (getVal ioA) >>= print -- 5 ?? expected 10

这定义了ioA ,所以我们可以用它自己的定义替换它。 我们得到:

main :: IO ()
main = do
  (getVal (newIO (5 :: Int))) >>= print -- 5
  setVal 10 (newIO (5 :: Int))
  (getVal (newIO (5 :: Int))) >>= print -- 5 ?? expected 10

现在我们可以看到问题了:我们创建了三个独立的向量。 问题是let ioA =...定义了一个 IO 操作(大致来说,一个命令式过程),我们可以稍后多次调用它。 但我们不希望这样:我们希望newIO (5:: Int)只执行一次。

为此,我们必须避免let并使用单子绑定( <- ,在do块中)。

main :: IO ()
main = do
  ioA <- newIO (5 :: Int)   -- run the action, just once
  (getVal ioA) >>= print
  setVal 10 ioA
  (getVal ioA) >>= print

这将触发一堆类型错误,因为例如getVal不再传递 IO 操作,而是传递 IO 操作的结果 不过,这正是我们想要的,因此我们需要相应地修复类型。

首先在此处删除IO

data A a = A
  { ioVal :: M.MVector (PrimState IO) a
  }

实际上,我们不想存储生成向量的过程,我们想要存储向量。

因此,我们需要删除<-以支持let其他几点。

getVal :: A a -> IO a
getVal = \aA -> do
  let val = ioVal aA  -- no IO action to run here
  M.read val 0

此外, newIO必须返回IO值。

newIO :: a -> IO (A a)
newIO = \a -> fmap A (newVal a)

我想你现在可以算出 rest 了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM