【问题标题】:How to modify or read a mutable vector passed as an argument in a function?如何修改或读取作为函数参数传递的可变向量?
【发布时间】:2016-06-10 14:46:22
【问题描述】:
  test :: VM.MVector s Int -> Int
  test x = runST $ do
    a <- return x
    VM.read a 0 -- Type error

我试图弄清楚如何不将 ST monad 中的所有内容放入单个函数中。如果我试图修改x 或从中返回一个值,编译器会抱怨可变向量的状态部分不匹配。

是否可以在 Haskell 中对传递的可变向量进行操作,还是我必须在对它们进行任何操作之前将它们冻结为不可变的对应物?

编辑:

这是实际的错误。

Couldn't match type `s1' with `s'
  `s1' is a rigid type variable bound by
       a type expected by the context: ST s1 Int at rjb.hs:17:12
  `s' is a rigid type variable bound by
      the type signature for test :: VM.MVector s Int -> Int
      at rjb.hs:16:11
Expected type: VM.MVector
                 (Control.Monad.Primitive.PrimState (ST s1)) Int
  Actual type: VM.MVector s Int
Relevant bindings include
  a :: VM.MVector s Int (bound at rjb.hs:18:5)
  x :: VM.MVector s Int (bound at rjb.hs:17:8)
  test :: VM.MVector s Int -> Int (bound at rjb.hs:17:3)
In the first argument of `VM.read', namely `a'
In a stmt of a 'do' block: VM.read a 0

编辑:以下通过类型检查。

  test :: VM.MVector (Control.Monad.Primitive.PrimState IO) Int -> IO (Int)
  test x = VM.read x 0

我猜我也可以改变x 向量。所以……

【问题讨论】:

  • 你能补充一下实际的错误吗?
  • a &lt;- return x 是多余的。这只是再次给你x
  • @Carsten 添加了错误。
  • 如果你包含你的导入会有所帮助。
  • 如果你想改变一个单子向量,你必须返回一个单子值。这就是 monad 的全部意义:副作用必须出现在类型中。 VM.MVector s Int -&gt; Int 类型的函数必然是一个常量函数。

标签: haskell vector monads mutable


【解决方案1】:

你可能需要一些例子。这是一个基本的评论,但如果你谷歌一下,我相信你会在网上找到其他人。

import Control.Monad.ST
import qualified Data.Vector.Mutable as VM

-- This returns a reference to a vector, wrapped in the ST s monad.
test :: ST s (VM.MVector s Int)
test = do
  v <- VM.new 10       -- create vector
  VM.write v 3 2000    -- modify it
  VM.write v 4 3000
  x <- VM.read v 3     -- access it
  VM.write v 4 (x+1)   
  return v             -- return it

-- This instead returns a (wrapped) Int
test2 :: ST s Int
test2 = do
  v <- test            -- call test, which performs the allocation
  VM.read v 4          -- return v[4]

-- This returns a plain pure Int value    
test3 :: Int
test3 = runST test2

请注意,runST x 只能在 x 的类型为 polytype ST s T 其中T 不涉及类型变量s。 这就是 ST monad 实现引用透明性的方式。

用更简单的术语来说,这意味着runST 绝不能返回任何指向已分配内存的“指针”。当runST 返回时,可以释放可变事物的每个分配。因此,典型的ST s 计算仅在最后执行runST,当它准备好丢弃所有可变数据并保留其中的不可变部分时。在上面的示例中,不可变部分是第 4 个元素(照常从 0 开始计数),即不可变的 Int

如果您不熟悉ST s,我建议您暂时忘记向量,并使用STRef s Int(参考Int)和ST 进行一些练习。任何ST 教程就足够了。

【讨论】:

  • 对,这就是我要找的。这就是 ST monad 的类型签名的样子。可变向量和 ST monad 具有相同的 s 类型。实际上,s 内部的那些 s 除了防止我无意中改变向量之外应该做什么?
  • @MarkoGrdinic s 是一个虚拟类型,它会“污染”所有“携带指针”的东西,例如 STRef s IntMVector s Int。它的目的是防止你从runST返回这些“指针”,仅此而已——它只是为了向编译器证明你遵守了规则。
  • @chi IIRC 这也是为了防止您不安全地交错在单独的内存块上运行的 ST 操作。因此,如果不先运行所有 foo,就不能尝试在 bar 中引用在块 foo 中创建的指针。
猜你喜欢
  • 1970-01-01
  • 2019-09-23
  • 1970-01-01
  • 2020-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-08
  • 1970-01-01
相关资源
最近更新 更多