Opened 15 months ago

Last modified 9 months ago

#15358 new feature request

no way to talk about unpacking sum types / unpacking tuples

Reported by: chessai Owned by:
Priority: normal Milestone: 8.10.1
Component: Compiler Version: 8.4.3
Keywords: unboxedsums, unboxedtuples Cc: osa1, andrewthad
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:


Suppose I have the following Haskell module:

{-# LANGUAGE BangPatterns #-}

-- strict 'Maybe'
data StrictMaybe a = SNothing | SJust !a

-- lazy 'Maybe'
data Maybe a = Nothing | Just a

data BoxedInner = BoxedInner
  !(Maybe Int)

data StillBoxedInner = StillBoxedInner
  !(StrictMaybe Int)

mBoxed :: BoxedInner
mBoxed = BoxedInner 0 (Just 0)

mWantThisToUnbox :: StillBoxedInner
mWantThisToUnbox = StillBoxedInner 1 (Just 1)

the 'StrictMaybe' can unbox the first 'Int' into 1#, but the 1 inside of the just cannot unbox. When compiled to core with -O2 what I'd want to see is something like:

mWantThisToUnbox = StillBoxedInner 0# (# | 1# #)

(where (# (# #) | a #) is an unboxed sum type with two constructors, one nullary and one unary)

but instead the Int inside 'SJust' remains boxed.

Even with something like the following:

{-# LANGUAGE UnboxedSums #-}
data UMaybe a = (# (# #) | a #)

something like 'UMaybe Int' would still result in 'Int' being boxed.

This same thing occurs with unpacked tuples, consider something like:

data StrictTuple = StrictTuple
  !(Int, Int)

Anything inside the (Int, Int) tuple will not unbox, despite having a bang pattern there.

Change History (3)

comment:1 Changed 15 months ago by osa1

If I understand correctly you want two things:

  1. Unpacking polymorphic fields
  2. Deeply unpacking strict fields

(1) gets requested from time to time and it's not something that can be implemented easily, it deserves a detailed design and a proposal.

(2) already works today. E.g.

{-# LANGUAGE BangPatterns #-}

module Lib where

data StrictIntPair = StrictIntPair {-# UNPACK #-} !Int {-# UNPACK #-} !Int

data StrictTuple = StrictTuple
  {-# UNPACK #-} !Int
  {-# UNPACK #-} !StrictIntPair

If you look at worker functions for StrictIntPair and StrictTuple constructors:

Lib.$WStrictIntPair [InlPrag=INLINE[2]]
  :: GHC.Types.Int -> GHC.Types.Int -> Lib.StrictIntPair
 Unf=OtherCon []] =
    [] \r [dt_s1aj dt_s1ak]
        case dt_s1aj of {
          GHC.Types.I# dt_s1am [Occ=Once] ->
              case dt_s1ak of {
                GHC.Types.I# dt_s1ao [Occ=Once] ->
                    Lib.StrictIntPair [dt_s1am dt_s1ao];

Lib.$WStrictTuple [InlPrag=INLINE[2]]
  :: GHC.Types.Int -> Lib.StrictIntPair -> Lib.StrictTuple
 Unf=OtherCon []] =
    [] \r [dt_s1ac dt_s1ad]
        case dt_s1ac of {
          GHC.Types.I# dt_s1af [Occ=Once] ->
              case dt_s1ad of {
                Lib.StrictIntPair dt_s1ah [Occ=Once] dt_s1ai [Occ=Once] ->
                    Lib.StrictTuple [dt_s1af dt_s1ah dt_s1ai];

Notice that StrictIntPair unpacks Ints, and StrictTuple uses those unpacked Ints.

In your example you have two problems:

  • In the first example the data type is polymorphic on the field so you can't unpack the SJust field even if it's strict.
  • In StrictTuple you can't unpack Ints because the tuple is not strict in its fields. If you define a strict tuple as I did in my example you'll see that you get three unboxed Ints as fields in StrictTuple.

Finally, when trying these out make sure you're using explicit {-# UNPACK #-} pragmas (otherwise it's hard to know if your field will be unpacked) and use -O (or -O2) as otherwise UNPACK pragmas don't work and you don't get automatic unpacking of small fields (e.g. Ints).

comment:2 Changed 14 months ago by bgamari


This certainly won't happen for 8.6.

comment:3 Changed 9 months ago by osa1


Bumping milestones of low-priority tickets.

Note: See TracTickets for help on using tickets.