Haskell Data.Vector.modify在每次迭代中创建向量副本

Haskell Data.Vector.modify在每次迭代中创建向量副本,haskell,optimization,vector,Haskell,Optimization,Vector,举个例子: import qualified Data.Vector.Unboxed as Vector import Data.Vector.Unboxed (Vector) import qualified Data.Vector.Unboxed.Mutable as MVector process :: [Int] -> Vector Int -> Vector Int process [] v = v process (x:xs) v = process xs $ Vect

举个例子:

import qualified Data.Vector.Unboxed as Vector
import Data.Vector.Unboxed (Vector)
import qualified Data.Vector.Unboxed.Mutable as MVector

process :: [Int] -> Vector Int -> Vector Int
process [] v = v
process (x:xs) v = process xs $ Vector.modify modify v
  where
  modify mv = do
    old <- MVector.read mv x
    MVector.write mv x (old + 1)

main :: IO ()
main = do
  print $ process [1, 1, 3, 1] $ Vector.replicate 10 0
还有
规则

"clone/new [Vector]" forall p.
  clone (new p) = p
根据我(相当有限)的理解,连续两次
modify
不应创建中间副本:

modify p2 . modify p1
=> new . New.modify p2 . clone . new . New.modify p1 . clone
=> new . New.modify p2 . New.modify p1 . clone
为什么它在
过程中不起作用?我认为应该:

process [1, 2] v
=> process [2] $ Vector.modify modify v
=> process [] $ Vector.modify modify $ Vector.modify modify v
=> Vector.modify modify $ Vector.modify modify v
=> the same as above

我怎样才能使它工作呢?

我认为是递归阻止了它

源代码中没有一个地方会说
modify
,后面紧跟着
modify
。函数的每次迭代都会再次调用
modify
,但这发生在运行时,而不是编译时。我想这就是问题所在。如果您要在一行中手动编写三个
modify
调用,它们会融合


我想不出一个办法来自动熔断。当然,您可以自己手动调用
clone
new
,但我想不出一种方法让编译器为您执行此操作。

为什么不生成一个调用
modify

import Control.Monad (forM_)

[...]

process :: [Int] -> Vector Int -> Vector Int
process xs v = Vector.modify modify v
  where
  modify mv = forM_ xs $ \ x -> do
    old <- MVector.read mv x
    MVector.write mv x (old + 1)
import-Control.Monad(表单)
[...]
进程::[Int]->Vector Int->Vector Int
进程xs v=Vector.modify v
哪里
修改mv=forM_xs$\x->do

老啊,递归阻止内联,所以规则不会触发。对吗?是的,规则是一种句法上的东西。如果它找到与规则中的表达式匹配的表达式,则会激发。它关注内联,所以它可以找到更多的东西,但它仍然需要在语法上找到它,因为我已经有了折叠数据的纯函数(实际上它不是一个列表)。我可以实现一元版本,但在此之前,我想知道为什么不能重用现有版本。@Yuras我恐怕不理解你的评论。
过程
函数基本上是一个
foldl(Vector.modify…
)。我使用的是自定义数据类型,不是列表,但想法是一样的。对于我的数据类型,我的函数类似于
foldl
,但还没有用于
foldM
的模拟函数。而且它不是可遍历的
实例,所以我不能使用
表单

import Control.Monad (forM_)

[...]

process :: [Int] -> Vector Int -> Vector Int
process xs v = Vector.modify modify v
  where
  modify mv = forM_ xs $ \ x -> do
    old <- MVector.read mv x
    MVector.write mv x (old + 1)