アレイにはO(1)インデックスがあります。問題は、各要素が遅れて計算されることです。だから、これはあなたがGHCiの中でこれを実行すると何が起こるかです:検索が非常に高速であること
*Main> :set +s
*Main> let t = 100000
(0.00 secs, 556576 bytes)
*Main> let a = fibArray t
Loading package array-0.4.0.0 ... linking ... done.
(0.01 secs, 1033640 bytes)
*Main> a!t -- result omitted
(1.51 secs, 570473504 bytes)
*Main> a!t -- result omitted
(0.17 secs, 17954296 bytes)
*Main>
注意、後にそれが既に一度見上げされています。 array
関数は、最終的に値を生成するために計算されるサンクへのポインタの配列を作成します。初めて価値を評価するときは、この費用を支払うことになります。ここでa!t
を評価するためのサンクの最初の数拡張は以下のとおりです。
a!t -> a!(t-1)+a!(t-2)-> a!(t-2)+a!(t-3)+a!(t-2) -> a!(t-3)+a!(t-4)+a!(t-3)+a!(t-2)
それは高価だ計算自体のコストではない、むしろそれは、この非常に大きなサンクを作成し、通過する必要があります。
array
に渡されたリストの値を厳密にしようとしましたが、それは無限ループに終わったようです。
これを回避する一般的な方法の1つは、STArrayなどの可変配列を使用することです。配列の作成中に使用可能になると要素を更新し、最終結果をフリーズして戻すことができます。ベクターパッケージでは、create
とconstructN
の関数がこれを簡単に行う方法を提供します。
-- constructN :: Unbox a => Int -> (Vector a -> a) -> Vector a
import qualified Data.Vector.Unboxed as V
import Data.Int
fibVec :: Int -> V.Vector Int64
fibVec n = V.constructN (n+1) c
where
c v | V.length v == 0 = 0
c v | V.length v == 1 = 1
c v | V.length v == 2 = 1
c v = let len = V.length v
in v V.! (len-1) + v V.! (len-2)
しかし、fibVec
機能は、箱なしのベクトルで動作します。規則的なベクトル(および配列)は厳密ではないので、あなたがすでに見つけたのと同じ問題に戻る。残念ながら、Integer
のUnboxedインスタンスはありません。無制限の整数型が必要な場合(このテストではすでにfibVec
がオーバーフローしています)、可変配列をIO
またはST
に作成して、必要な厳密性を有効にしています。あなたのfibArray
例を特に参照
モノリシックアレイとはどういう意味ですか? – luqui
'IO(U)Array'と' ST(U)Array'はモノリシックに見えません... –
効率的でないコードの短い例を挙げて、用語をゼロにすることはできますか? –