I have a dynamic programming algorithm and I find my Haskell implementation very satisfying, as it allows me to define the master array recursively, like so:
fill :: Int -> Int -> Entry
fill 0 0 = Entry Origin 0.0
fill 0 j = ...
fill i 0 = ...
fill i j = f m i j
m :: Array (Int, Int) Entry
m = listArray dims [fill i j | (i, j) <- range dims]
where f is a moderately complex function referring back to the main array m. The Entry type is just a Double with a small annotation.
The data itself is quite large, and m ends up having on the order of 100M entries. The algorithm is still blazing fast, but it uses ~25GB RAM in the process. From reading around I understand that this is because it keeps around the full computation of the array entries instead of the final value, but if I switched to unboxed arrays, I could not define them recursively like in the example above.
Is there a way to have a cake (low memory footprint) and eat it (recursive definition)?
Entrytype stricter, e.g. by adding strictness annotation and/or unpacking. You can't avoid the boxing ofEntryitself and use an unboxed array, but you probably can remove boxing from the components ofEntry. How is that type defined?data Entry = Entry Source Double,data Source = Origin | Left | Right | Top | Bottom. So super simple. I believe that unboxing theDoublepart could help, because that's the recursively defined part. @luqui I'd estimate that maybe half of the entries are actually used, and memory profiling supports that. @DanielWagner I'm curious what you have in mind. In principle, 25 GB at any stage is a bit heavy, since I'd like to eventually run this on smaller machines, but I'm definitely listening.data Entry = Entry {-# UNPACK #-} !Source {-# UNPACK #-} !Doublefor such a basic type. Don't forget to turn on optimizations with-O(and to avoid GHCi for measuring performance)