几天来,我一直在努力构建一个具有可变值的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的基本行为,我尝试创建、读取、(Re)写和(Re)读取字段的可变值;但是,它不像集应该执行的那样工作。
密码怎么了?请给我建议。
发布于 2022-02-10 23:15:03
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)我想你现在可以弄清楚剩下的了。
https://stackoverflow.com/questions/71073253
复制相似问题