我想以递归方式生成一个未装箱的矢量。举个简单的例子:
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
,代码将会挂起。我理解为什么会这样,但我仍然希望能够做一个递归定义并获得未装箱的矢量的速度。这样做有可能吗?
答案 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)索引,所以它应该相当快。