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