Haskell 哈斯克尔。更新O(1)中的单个矢量元素
我想写一个函数来更新O(1)中的单个向量元素: 复制整个向量很容易更新值:Haskell 哈斯克尔。更新O(1)中的单个矢量元素,haskell,vector,Haskell,Vector,我想写一个函数来更新O(1)中的单个向量元素: 复制整个向量很容易更新值: upd v ind x = v // [(ind,x)] 但这太慢了 我创建了一个向量,名为Data.vector.Generic.fromList,不冻结它 要在适当的位置修改向量,我找到了函数 Data.Vector.modify、Data.Vector.Mutable.write和Data.Vector.Mutable.unsafeWrite,但我不知道如何使用它们 当我尝试这个: upd v ind x = d
upd v ind x = v // [(ind,x)]
但这太慢了
我创建了一个向量,名为Data.vector.Generic.fromList
,不冻结它
要在适当的位置修改向量,我找到了函数
Data.Vector.modify
、Data.Vector.Mutable.write
和Data.Vector.Mutable.unsafeWrite
,但我不知道如何使用它们
当我尝试这个:
upd v ind x = do DVM.write v ind x
编译器抱怨:
Couldn't match type `()' with `Integer'
Expected type: DV.Vector Integer
Actual type: DV.Vector ()
In the return type of a call of `DVM.write'
In a stmt of a 'do' block: DVM.write v ind x
In the expression: do { DVM.write v ind x }
(DV=Data.Vector
,DVM=Data.Vector.Mutable
)
感谢您的帮助。
我非常乐意得到一个使用
Data.Vector.modify
的例子 首先请注意,具有单个表达式的do
块始终与其自身的表达式相同。所以你也可以写
upd v ind x = DVM.write v ind x
但出于几个原因,这没有意义
v
仍然是一个不可变的向量。可变向量是完全不同的,它们是通过引用一个PrimMonad
的状态来实现的——纯Haskell计算通常不需要类似的东西,因为引用透明性保证状态总是相同的。当然,这正是阻止您在O(1)中进行更新的原因,并且没有真正的方法可以绕过这一点。您需要输入其中一个单子才能获得此类更新- 将可变向量冻结为不可变向量,并将其作为结果返回。当然,这也只能通过一份完整内容的副本来安全地完成,因此它不会比简单得多的
解决方案带来任何好处/
- 只要你需要更新,就呆在单子里。你永远不会冻结向量太久,它只是在可变状态下保持“浮动”。这意味着您不能拥有像
这样的函数签名,而只需要使用一元动作。正如Louis Wasserman所说,这正是upd
已经在做的事情,所以你真的不需要做更多的事情了。(这是有道理的:如果您设想的write
这样的函数是可能的,那么它肯定已经在upd
库中了。)vector
upd
的上下文。然而,在您完全变之前:为什么您如此确定一个简单的纯更新会降低您的速度?vector
库非常擅长通过流融合“批处理”这样的更新;如果您正在进行O(n)个独立的更新,那么avarage上的每个更新都可以是O(1),因为所有更新只生成一个副本
1当你将载体注入单子以使其可变时,解冻可能也需要一个拷贝。你所要求的只是:
> :t modify (\mv -> write mv 10 'a')
modify (\mv -> write mv 10 'a') :: Vector Char -> Vector Char
> modify (\mv -> write mv 10 'a') (fromList "Hello good comrades")
fromList "Hello goodacomrades"
> modify (\mv -> unsafeWrite mv 0 100) (fromList [1..20::Integer])
fromList [100,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
继续你提到的其他行动:
> :t thaw (fromList "Hello good comrades") >>= \mv -> write mv 10 'a'
thaw (fromList "Hello good comrades") >>= \mv -> write mv 10 'a'
:: Control.Monad.Primitive.PrimMonad m => m () -- i.e. IO or ST s
> :t thaw (fromList "Hello good comrades") >>= \mv -> write mv 10 'a' >> freeze mv
thaw (fromList "Hello good comrades") >>= \mv -> write mv 10 'a' >> freeze mv
:: Control.Monad.Primitive.PrimMonad m => m (Vector Char)
> :t thaw (fromList "Hello good comrades") >>= \mv -> write mv 10 'a' >> freeze mv >>= print
thaw (fromList "Hello good comrades") >>= \mv -> write mv 10 'a' >> freeze mv >>= print
:: IO ()
> thaw (fromList "Hello good comrades") >>= \mv -> write mv 10 'a' >> freeze mv >>= print
fromList "Hello goodacomrades"
现在为runST导入Control.Monad.ST
> :t runST
runST :: (forall s. ST s a) -> a
> :t thaw (fromList "Hello good comrades") >>= \mv -> write mv 10 'a'
thaw (fromList "Hello good comrades") >>= \mv -> write mv 10 'a'
:: Control.Monad.Primitive.PrimMonad m => m () -- we will use ST s
> :t runST $ thaw (fromList "Hello good comrades") >>= \mv -> write mv 10 'a' >> freeze mv
runST $ thaw (fromList "Hello good comrades") >>= \mv -> write mv 10 'a' >> freeze mv
:: Vector Char
> runST $ thaw (fromList "Hello good comrades") >>= \mv -> write mv 10 'a' >> freeze mv
fromList "Hello goodacomrades"
这就是为什么给runST
的参数与给modify
的参数类似,这对于法向量是不可能的;您必须使用可变向量来执行此操作。您的意思是我的函数必须是Data.vector.mutable.MVector->Int->Integer Data.vector.mutable.MVector类型吗?呃,不完全是。你需要的函数正是write函数,你想要的类型正是它的类型。我相信在最坏的情况下,冻结和解冻都需要拷贝。例如,do{vThank you,我将更改代码以保持在一个单独的圣莫纳德内。谢谢!现在我知道为什么解冻很重要了。
> :t runST
runST :: (forall s. ST s a) -> a
> :t thaw (fromList "Hello good comrades") >>= \mv -> write mv 10 'a'
thaw (fromList "Hello good comrades") >>= \mv -> write mv 10 'a'
:: Control.Monad.Primitive.PrimMonad m => m () -- we will use ST s
> :t runST $ thaw (fromList "Hello good comrades") >>= \mv -> write mv 10 'a' >> freeze mv
runST $ thaw (fromList "Hello good comrades") >>= \mv -> write mv 10 'a' >> freeze mv
:: Vector Char
> runST $ thaw (fromList "Hello good comrades") >>= \mv -> write mv 10 'a' >> freeze mv
fromList "Hello goodacomrades"