Data.Vector.Mutable 字段不能 written/set 正确? : Haskell
Data.Vector.Mutable field can not be written/set properly? : Haskell
几天来我一直在努力编写一个 data
结构,该结构的可变值字段为 Data.Vector.Mutable
我确认 Data.Vector.Mutable
本身的行为符合我的预期;然而,一旦它被包含在一个结构中,就会以某种方式停止与我的期望相反。
下面是一个演示代码,其中仅包含 newVal
、getVal
和 setVal
以结构的可变字段值为目标。
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 的基本行为,我尝试创建、读取、(重新)写入和(重新)读取字段的可变值;然而,它并没有像 set 应该执行的预期那样工作。
代码有什么问题?请指教
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 操作的 result。不过,这正是我们想要的,因此我们需要相应地修复类型。
首先在此处删除 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
必须 return 一个 IO
值。
newIO :: a -> IO (A a)
newIO = \a -> fmap A (newVal a)
我想你现在可以想出剩下的了。
几天来我一直在努力编写一个 data
结构,该结构的可变值字段为 Data.Vector.Mutable
我确认 Data.Vector.Mutable
本身的行为符合我的预期;然而,一旦它被包含在一个结构中,就会以某种方式停止与我的期望相反。
下面是一个演示代码,其中仅包含 newVal
、getVal
和 setVal
以结构的可变字段值为目标。
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 的基本行为,我尝试创建、读取、(重新)写入和(重新)读取字段的可变值;然而,它并没有像 set 应该执行的预期那样工作。
代码有什么问题?请指教
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 操作的 result。不过,这正是我们想要的,因此我们需要相应地修复类型。
首先在此处删除 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
必须 return 一个 IO
值。
newIO :: a -> IO (A a)
newIO = \a -> fmap A (newVal a)
我想你现在可以想出剩下的了。