Consider the following data model utilizing an existential:
data Node a = Node a (Map TypeRep AnyNode)
data AnyNode = forall a. Show a => AnyNode a
The rules about memory footprint of standard types have been explained previously. Now, what are the rules for existential types, like AnyNode?
Are there any optimization techniques, e.g. some workarounds using unsafeCoerce making it possible to elude the existential declaration? I'm asking this because a type similar to Node is going to be placed in a cost centre of a highly memory-intensive lib, so memory footprint is all, that's why the most dirty hacks are welcome.
The ghc-datasize package may be of help here:
{-# LANGUAGE RankNTypes, GADTs #-}
import GHC.DataSize
data Node = forall a. Show a => Node a
main = do
s <- closureSize $ Node 0
print s -- 24 bytes on my 64-bit system
So, it seems that Node takes one extra word compared to the plain unary data constructor, presumably because of the Show class dictionary pointer. Also, I tried adding more class constraints to Node, and each of them takes one extra word of space.
I don't know for sure whether it is possible to magic away the dictionary pointer in specific circumstances. I think it isn't possible if you'd like to keep the existential type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With