Haskell 哈斯克尔。更新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

我想写一个函数来更新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 = 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)中进行更新的原因,并且没有真正的方法可以绕过这一点。您需要输入其中一个单子才能获得此类更新
  • 因为可变向量在monad的状态中是“隐藏”的,所以不能简单地将它们作为函数结果单独返回。这将向纯函数式语言泄漏状态,从而违反引用透明性。您有两个选择:
    • 将可变向量冻结为不可变向量,并将其作为结果返回。当然,这也只能通过一份完整内容的副本来安全地完成,因此它不会比简单得多的
      /
      解决方案带来任何好处
    • 只要你需要更新,就呆在单子里。你永远不会冻结向量太久,它只是在可变状态下保持“浮动”。这意味着您不能拥有像
      upd
      这样的函数签名,而只需要使用一元动作。正如Louis Wasserman所说,这正是
      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"