Data.Vector.dropWhile的有效替代方案

Nic*_*lev 7 haskell vector data-structures

考虑以下:

module Main where

import           Criterion.Main
import qualified Data.Vector    as V

f1 :: V.Vector Double -> Double
f1 xs
  | V.null xs = 0
  | otherwise = V.last xss / V.head xss
    where xss = V.dropWhile (< 10) xs

f2 :: V.Vector Double -> Double
f2 xs
  | V.null xs = 0
  | otherwise = V.last xs / V.head xs

setupEnv :: IO (V.Vector Double)
setupEnv = return $ V.enumFromN 0 10000000

main :: IO ()
main = defaultMain [
  env setupEnv $ \v ->
    bgroup "funcs" [bench "f1" $ nf f1 v , bench "f2" $ nf f2 v]
  ]
Run Code Online (Sandbox Code Playgroud)

使用--make -O2和运行编译会产生以下结果:

app $ ./A
benchmarking funcs/f1
time                 81.87 ms   (78.34 ms .. 86.06 ms)
                     0.998 R²   (0.996 R² .. 1.000 R²)
mean                 85.87 ms   (84.16 ms .. 87.13 ms)
std dev              2.351 ms   (1.169 ms .. 3.115 ms)

benchmarking funcs/f2
time                 27.50 ns   (27.11 ns .. 27.95 ns)
                     0.998 R²   (0.996 R² .. 0.999 R²)
mean                 27.62 ns   (27.21 ns .. 28.05 ns)
std dev              1.391 ns   (1.154 ns .. 1.744 ns)
variance introduced by outliers: 73% (severely inflated)
Run Code Online (Sandbox Code Playgroud)

简单地取第一个和最后一个元素并将它们分开的平均执行时间是~27ns.丢弃前9个元素并执行相同操作的平均值约为85毫秒或慢3000倍.

使用未装箱的向量可将性能提高f1一半以上,但我需要支持没有"Unboxed"类实例的元素.

根据dropWhile文档,它具有O(n)的复杂性,但它没有复制.Haskell库中是否有数据结构支持高效的dropWhile类型操作以及对第一个和最后一个元素的O(1)访问?

And*_*ács 4

的有Vector问题dropWhile。我认为流融合很可能无法正确启动,并且我们为昂贵的流/捆绑构建付出了代价。可能需要进行一些进一步的调查。

作为权宜之计,您可以实施自定义dropWhile. 我使用了您的基准测试和以下代码:

dropWhile' :: (a -> Bool) -> V.Vector a -> V.Vector a
dropWhile' p v = V.drop (go 0) v where
  go n | n == V.length v       = n
       | p (V.unsafeIndex v n) = go (n + 1)
       | otherwise             = n
Run Code Online (Sandbox Code Playgroud)

并得到以下结果:

benchmarking funcs/f1
time                 57.70 ns   (56.35 ns .. 59.46 ns)

benchmarking funcs/f2
time                 19.68 ns   (19.44 ns .. 19.91 ns)
Run Code Online (Sandbox Code Playgroud)