gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-05 01:05:04 24 4
gpt4 key购买 nike

我已经努力了好几天来编写一个 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 的基本行为,我尝试创建、读取、(重新)写入和(重新)读取字段的可变值;但是,它并没有像 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 Action (大致是一个命令式过程),我们可以在以后多次调用它。但我们不想要这样:我们想要 newIO (5 :: Int)只执行一次。

为此,我们必须避免let并使用一元绑定(bind)( <- ,在 do block 中)。

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必须返回 IO值(value)。

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

我想你现在可以弄清楚其余的了。

关于haskell - Data.Vector.Mutable 字段无法正确写入/设置? : Haskell,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71073253/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com