29

I have trouble understanding how UNPACK works in Haskell. Consider, for example, the following data declarations:

data P a b = P !a !b
data T = T {-# UNPACK #-} !(P Int Int)

How will datatype T be unpacked? Will it be equivalent to

data T' = T' !Int !Int

or will the Ints be further unpacked:

data T'' = T'' Int# Int#

? What about

data U = U {-# UNPACK #-} !(P Int (P Int Int))

?

jub0bs
  • 60,866
  • 25
  • 183
  • 186
Alexey Vagarenko
  • 1,206
  • 8
  • 15

1 Answers1

33

The GHC documentation describes the UNPACK pragma as follows:

The UNPACK indicates to the compiler that it should unpack the contents of a constructor field into the constructor itself, removing a level of indirection.


How will datatype T be unpacked?

data T = T (P Int Int) corresponds to

non-unpacked data

Therefore, data T = T {-# UNPACK #-} !(P Int Int) corresponds to

pair unpacked

In plain English, UNPACK has unpacked the contents of constructor P into the field of constructor T, removing one level of indirection and one constructor header (P).

data T = T {-# UNPACK #-} !(P Int Int) isn't as "compact" as data T'' = T'' Int# Int#:

completely unpacked


What about

data U = U {-# UNPACK #-} !(P Int (P Int Int))

?

Similarly, data U = U (P Int (P Int Int)) corresponds to

pair of pairs

and data U = U {-# UNPACK #-} !(P Int (P Int Int)) corresponds to

unpacked pair of pairs

In plain English, UNPACK has unpacked the contents of constructor P into the field of constructor U, removing one level of indirection and one constructor header (P).

Resources

jub0bs
  • 60,866
  • 25
  • 183
  • 186
  • So, there is no way to unpack `T` to `T''` i.e. remove two levels of constructors? – Alexey Vagarenko Nov 26 '15 at 08:36
  • 1
    @Zeta Thanks for the edit. How did you produce those beautiful diagrams? TikZ? The `diagrams` library? – jub0bs Nov 26 '15 at 08:58
  • 8
    @Jubobs: I used `dot` aka GraphViz: `digraph { node[shape=record]; con[label="U|"]; p[label="P||"]; q[label="P||"]; i1[label="I#|Int#"]; i2[label="I#|Int#"]; i3[label="I#|Int#"]; con:f0 -> p:p0 p:p1 -> i1:i1 p:p2 -> q:q0 q:q1 -> i2:i2 q:q2 -> i3:i3 }`. Not really really what I would call best practice graphviz, but it did the job. – Zeta Nov 26 '15 at 12:48
  • @Zeta Thanks for that. – jub0bs Nov 26 '15 at 12:55
  • @AlexeyVagarenko It seems that polymorphic fields (e.g. `a` and `b` in the data declaration of `P`) cannot ([yet?](https://ghc.haskell.org/trac/ghc/ticket/7647)) be unpacked. I may be wrong, but I don't think you can unpack `T` so that it has the same memory footprint as `T''`. – jub0bs Nov 27 '15 at 07:10