可以使用未装箱的向量进行递归定义吗?

时间:2016-07-05 14:43:29

标签: haskell recursion vector

我想以递归方式生成一个未装箱的矢量。举个简单的例子:

import qualified Data.Vector as V

fib :: V.Vector Int
fib = V.generate 10 f
  where
    f 0 = 0
    f 1 = 1
    f x = (fib V.! (x - 1)) + (fib V.! (x - 2))

该函数正确生成斐波那契序列。但是,如果我改为使用Data.Vector.Unboxed,代码将会挂起。我理解为什么会这样,但我仍然希望能够做一个递归定义并获得未装箱的矢量的速度。这样做有可能吗?

3 个答案:

答案 0 :(得分:5)

一种可能性是使用未装箱的可变向量,并在构建完成后冻结

import Control.Monad.ST (runST)
import Control.Monad (forM_, ap)
import qualified Data.Vector.Unboxed as U
import qualified Data.Vector.Unboxed.Mutable as M

fib :: Int -> U.Vector Int
fib s = runST $ M.new s >>= ap ((>>) . forM_ [0..s - 1] . f) U.unsafeFreeze
    where
    f v 0 = M.write v 0 0
    f v 1 = M.write v 1 1
    f v i = do
        a <- M.read v (i - 1)
        b <- M.read v (i - 2)
        M.write v i (a + b)

答案 1 :(得分:5)

即使在未装箱的情况下,

constructN也能满足您的需求。下面,v是到目前为止构建的向量前缀,f v返回下一个元素。

最佳O(N)复杂度。

import qualified Data.Vector.Unboxed as V

fib :: V.Vector Int
fib = V.constructN 10 f
  where
    f v = case V.length v of
            0 -> 0
            1 -> 1
            n -> (v V.! (n - 1)) + (v V.! (n - 2))

答案 2 :(得分:3)

我能想到的唯一方法是生成一个惰性递归列表,然后将其转换为未装箱的矢量。

标准的令人困惑的咒语

fibs = 1 : 1 : zipWith (+) fibs (tail fibs)

将为您提供无限的Fibonacci数字列表。然后,您可以从中构建一个未装箱的列表,此后将进行快速索引。

当然,实际上并没有使用向量来计算计算斐波纳契数。但它也没有对链表进行O(n)索引,所以它应该相当快。