这是question的延续。由于矢量库似乎没有可熔的O(1)更新函数,我想知道是否有可能编写一个不涉及unsafeFreeze
和{{1}的可熔O(1)更新函数}。它会使用unsafeThaw
表示,我猜 - 我不熟悉如何使用vector stream
和stream
编写一个 - 因此,这个问题。原因是这将使我们能够在向量上编写一个缓存友好的更新函数,其中只修改了一个狭窄的向量区域,因此,我们不想仅仅为了处理那个狭窄的区域而遍历整个向量(并且这个操作在每个函数调用中可能发生数十亿次 - 因此,保持开销非常低的动机)。转换函数如unstream
处理整个向量 - 所以它们会太慢。
我有一个我想做的玩具示例,但下面的map
函数使用upd
和unsafeThaw
- 它似乎没有在核心中进行优化,并且还打破了不再使用缓冲区的承诺:
unsafeFreeze
我知道如何使用module Main where
import Data.Vector.Unboxed as U
import Data.Vector.Unboxed.Mutable as MU
import Control.Monad.ST
upd :: Vector Int -> Int -> Int -> Vector Int
upd v i x = runST $ do
v' <- U.unsafeThaw v
MU.write v' i x
U.unsafeFreeze v'
sum :: Vector Int -> Int
sum = U.sum . (\x -> upd x 0 73) . (\x -> upd x 1 61)
main = print $ Main.sum $ U.fromList [1..3]
实现命令式算法。如果您想知道为什么这种替代方法,我想尝试使用纯矢量来检查特定算法的STVector
转换在使用可熔纯矢量流(使用monadic操作在引擎盖下)时的差异。课程)。
当使用GHC
编写算法时,它似乎没有像我希望的那样很好地迭代(我猜想当有很多可变性时GHC优化器更难发现循环散落在周围)。所以,我正在研究这种替代方法,看看我能在那里得到一个更好的循环。
答案 0 :(得分:4)
您编写的upd
函数看起来不是正确,更不用说是可融合的了。 Fusion是一个库级优化,需要您从某些原型中编写代码。在这种情况下,您想要的不仅仅是融合,而是recycling,可以通过//
和update
等批量更新操作轻松实现。这些操作会融合,甚至在很多时候都会发生。
如果你真的想编写自己的基于破坏性更新的代码,请不要使用unsafeThaw
- 使用modify
答案 1 :(得分:3)
任何功能都是可熔的更新功能;你似乎试图逃避编程模型,矢量包试图让你使用
module Main where
import Data.Vector.Unboxed as U
change :: Int -> Int -> Int
change 0 n = 73
change 1 n = 61
change m n = n
myfun2 = U.sum . U.imap change . U.enumFromStepN 1 1
main = print $ myfun2 30000000
- 这不会创建任何向量,更不用“更新”它们,因为您将看到是否研究核心。