提问人:Marko Grdinić 提问时间:6/10/2016 最后编辑:Marko Grdinić 更新时间:6/10/2016 访问量:1664
如何修改或读取在函数中作为参数传递的可变向量?
How to modify or read a mutable vector passed as an argument in a function?
问:
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
答:
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 x
x
ST s T
T
s
简单来说,这意味着任何指向已分配内存的“指针”都不能由 返回。当返回时,可以释放所有可变事物的分配。因此,典型的计算只在最后执行,当它准备好丢弃所有可变数据并保留其中的不可变部分时。在上面的示例中,不可变部分是第 4 个元素(像往常一样从 0 开始计数),这是一个不可变的 。runST
runST
ST s
runST
Int
如果你不熟悉 ,我建议你暂时忘记向量,并用 (引用 ) 和 做一些练习。任何教程就足够了。ST s
STRef s Int
Int
ST
ST
评论
0赞
Marko Grdinić
6/10/2016
是的,这就是我一直在寻找的。这就是 ST monad 的类型签名的样子。可变向量和 ST 单子具有相同的类型。实际上,除了防止我无意中改变向量之外,那些内部应该做什么?s
s
ST s (VM.MVector s Int)
7赞
chi
6/10/2016
@MarkoGrdinic 是一种虚拟类型,它“玷污”了所有“携带指针”的东西,例如 或 。它的目的是防止你返回这些“指针”,没有别的——它只是为了向编译器证明你遵守了规则。s
STRef s Int
MVector s Int
runST
0赞
semicolon
10/16/2016
@chi IIRC 这也是为了防止您不安全地交错在单独的内存块上运行的 ST 操作。因此,您不能尝试在不首先运行所有 of 的情况下引用在块中创建的指针。foo
bar
foo
评论
a <- return x
是多余的。那只是给你再次。x
VM.MVector s Int -> Int