厳密には、サンクが作成されていないことを必ずしも意味しているわけではなく、引数がbottomの場合も結果がbottomであることを意味します。しかし、accumArray
はそれほど厳密ではありません。それは中間の底から定義された値を生成する非厳密な関数を許さなければならないので、他に何もできません。厳密性解析器は、厳密であれば累積関数が各書き込みでWHNFに評価されるように書き直すことはできません。これは、プログラムの意味をかなり劇的に変更する(底辺と底辺を含む配列) 。
しかし、私はいくつかの分野で厳しいと熱心な機能の不幸な欠如があることに同意しました。あなたの問題のために
、あなたがより大きなスタックを(+RTS -K128M
はここに十分でなかったが、256Mがした)を使用することができ、またはあなたは、厳密な書き込みで
import Data.Array.Base (unsafeRead, unsafeWrite)
import Data.Array.ST
import GHC.Arr
strictAccumArray :: Ix i => (e -> a -> e) -> e -> (i,i) -> [(i,a)] -> Array i e
strictAccumArray fun ini (l,u) ies = case iar of
Array _ _ m barr -> Array l u m barr
where
iar = runSTArray $ do
let n = safeRangeSize (l,u)
stuff = [(safeIndex (l,u) n i, e) | (i, e) <- ies]
arr <- newArray (0,n-1) ini
let go ((i,v):ivs) = do
old <- unsafeRead arr i
unsafeWrite arr i $! fun old v
go ivs
go [] = return arr
go stuff
を使用することができ、サンクが小さく維持されているので、スタックオーバーフローはありません。しかし、リストには多くのスペースがありますので、リストが長すぎるとヒープが枯渇する可能性があります。それは使用上の結合機能の結果を強制insertWith'
、付属していますので
別のオプションは、(containersのバージョンが0.4.1.0である場合や、またはData.IntMap
)配列の代わりにData.Map
を使用することであろう。コードは、例えばMap
を使用しての
import qualified Data.Map as M -- or Data.IntMap
import Data.List (foldl')
histo :: M.Map Int (Int,[Int]) -- M.IntMap (Int,[Int])
histo = foldl' upd M.empty [(0,n) | n <- [0 .. 15000000]]
where
upd mp (i,n) = M.insertWith' add i (1,[n]) mp
add (j,val:_) (k,vals) = k `seq` vals `seq` (k+j,val:vals)
add _ pr = pr -- to avoid non-exhaustive pattern warning
欠点は、それはあなたのケースでは、もう少し複雑にする必要があるので、結合機能は、タイプa -> a -> a
を持っている必要があります
- あることができます。
- 更新はO(1)ではなくO(ログサイズ)です。したがって、大きなヒストグラムの場合、更新はかなり遅くなります。
Map
およびIntMap
には、ブックよりもオーバーヘッドがあるため、配列よりも多くのスペースが使用されます。しかし、更新のリストがインデックスの数と比較して大きい場合、その差は無視されます(オーバーヘッドはキーの値とは無関係にキーごとにk
ワードです)。この場合、値のサイズはそれぞれ更新。
ありがとうございました!ベンチマークを実行して、自分のデータに最も適しているものがあるかどうかを確認する必要があります。ヒープスペースは問題ではありません。私は実際に最初の10個の値とその数がどれくらいあるかだけを求めています。 –