如何修改或读取在函数中作为参数传递的可变向量?

How to modify or read a mutable vector passed as an argument in a function?

提问人:Marko Grdinić 提问时间:6/10/2016 最后编辑:Marko Grdinić 更新时间:6/10/2016 访问量:1664

问:

  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

哈斯克尔 向量 单子 可变

评论

0赞 Random Dev 6/10/2016
你能添加实际错误吗?
0赞 melpomene 6/10/2016
a <- return x是多余的。那只是给你再次。x
0赞 Marko Grdinić 6/10/2016
@Carsten 添加了错误。
0赞 ErikR 6/10/2016
如果您包括进口,那将会有所帮助。
0赞 chi 6/10/2016
如果要改变一元向量,则必须返回一元值。这就是单子的全部意义所在:副作用必须出现在类型中。类型的函数必然是常量函数。VM.MVector s Int -> Int

答:

9赞 chi 6/10/2016 #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

请注意,仅当 的类型为 polytype,其中不涉及类型变量。 这就是 ST monad 实现参照透明度的方式。runST xxST s TTs

简单来说,这意味着任何指向已分配内存的“指针”都不能由 返回。当返回时,可以释放所有可变事物的分配。因此,典型的计算只在最后执行,当它准备好丢弃所有可变数据并保留其中的不可变部分时。在上面的示例中,不可变部分是第 4 个元素(像往常一样从 0 开始计数),这是一个不可变的 。runSTrunSTST srunSTInt

如果你不熟悉 ,我建议你暂时忘记向量,并用 (引用 ) 和 做一些练习。任何教程就足够了。ST sSTRef s IntIntSTST

评论

0赞 Marko Grdinić 6/10/2016
是的,这就是我一直在寻找的。这就是 ST monad 的类型签名的样子。可变向量和 ST 单子具有相同的类型。实际上,除了防止我无意中改变向量之外,那些内部应该做什么?ssST s (VM.MVector s Int)
7赞 chi 6/10/2016
@MarkoGrdinic 是一种虚拟类型,它“玷污”了所有“携带指针”的东西,例如 或 。它的目的是防止你返回这些“指针”,没有别的——它只是为了向编译器证明你遵守了规则。sSTRef s IntMVector s IntrunST
0赞 semicolon 10/16/2016
@chi IIRC 这也是为了防止您不安全地交错在单独的内存块上运行的 ST 操作。因此,您不能尝试在不首先运行所有 of 的情况下引用在块中创建的指针。foobarfoo