Skip to content

Derived enum instances should support list fusion.

Motivation

List fusion improves performance so is desireable.

However it's currently not supported by Enum instances when derived by GHC.

Consider this case:


data T = A | B | C | D | E | F | G | H | I | J | K deriving (Enum)

bar = [A .. E]

If a use site maps over bar we would hope this would fuse with the enumeration.

In practice however we end up with Core like this:


Rec {
-- RHS size: {terms: 34, types: 21, coercions: 0, joins: 0/0}
MyEnum.$wgo [InlPrag=NOUSERINLINE[2], Occ=LoopBreaker]
  :: GHC.Prim.Int# -> (# T, [T] #)
[GblId, Arity=1, Str=<L,U>, Unf=OtherCon []]
MyEnum.$wgo
  = \ (w_s2SI :: GHC.Prim.Int#) ->
      (# case GHC.Prim.>=# w_s2SI 0# of {
           __DEFAULT -> MyEnum.$wlvl w_s2SI;
           1# ->
             case GHC.Prim.<=# w_s2SI 10# of {
               __DEFAULT -> MyEnum.$wlvl w_s2SI;
               1# -> GHC.Prim.tagToEnum# @ T w_s2SI
             }
         },
         case w_s2SI of wild_X13 {
           __DEFAULT ->
             case MyEnum.$wgo (GHC.Prim.+# wild_X13 1#) of
             { (# ww1_s2SN, ww2_s2SO #) ->
             GHC.Types.: @ T ww1_s2SN ww2_s2SO
             };
           4# -> GHC.Types.[] @ T
         } #)
end Rec }

-- RHS size: {terms: 7, types: 10, coercions: 0, joins: 0/0}
bar :: [T]
[GblId,
 Unf=Unf{Src=<vanilla>, TopLvl=True, Value=False, ConLike=False,
         WorkFree=False, Expandable=False, Guidance=IF_ARGS [] 40 30}]
bar
  = case MyEnum.$wgo 0# of { (# ww1_s2SN, ww2_s2SO #) ->
    GHC.Types.: @ T ww1_s2SN ww2_s2SO
    }

Which won't support list fusion. The recursive go function doesn't get a unfolding at all.

Even if it did it would need to be implemented differently to support fusion.

Proposal

The implementation should be changed to make bar a good producer for list fusion.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information