Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory footprint of existentially quantified types and related optimization techniques

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.

like image 565
Nikita Volkov Avatar asked Nov 26 '13 12:11

Nikita Volkov


1 Answers

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.

like image 147
András Kovács Avatar answered Sep 20 '22 04:09

András Kovács