Skip to content

Demand analyser should unpack tuple dictionaries

Consider

{-# OPTIONS_GHC -O -fdicts-strict #-}
module Foo where

type PairDict a = (Eq a, Show a)

foo :: PairDict a => a -> a -> String
foo x y | x==y      = show x
        | otherwise = show y

At the moment, with -O we generate this:

foo :: forall a. PairDict a => a -> a -> String
[GblId,
 Str=<SP(SP(1C(1,C(1,L)),A),SP(A,1C(1,L),A))><L><L>,
 Unf=Unf{Src=<vanilla>, TopLvl=True]
foo
  = \ (@a_aPr)
      ($d(%,%)_aPs :: PairDict a_aPr)
      (eta_B0 :: a_aPr)
      (eta1_B1 :: a_aPr) ->
      case ==
             @a_aPr
             (GHC.Classes.$p0(%,%) @(Eq a_aPr) @(Show a_aPr) $d(%,%)_aPs)
             eta_B0
             eta1_B1
      of {
        False ->
          show
            @a_aPr
            (GHC.Classes.$p1(%,%) @(Eq a_aPr) @(Show a_aPr) $d(%,%)_aPs)
            eta1_B1;
        True ->
          show
            @a_aPr
            (GHC.Classes.$p1(%,%) @(Eq a_aPr) @(Show a_aPr) $d(%,%)_aPs)
            eta_B0
      }

Notice that we are strict in the pair dictionary, but we do not unpack it. Why not? Because of Note [Do not unbox class dictionaries] in GHC.Core.Opt.DmdAnal.

But for tuple dictionaries it would be better to unpack. Then we'd get

$wfoo :: (Eq a, Show a) => blah

and we might well be able to specialise it for particular Eq or Show dictionaries. The above Note doesn't apply.

Actually for "equality classes" like

bar :: (a ~ b) => blah

we would also be better off unboxing. Not much point in specialising bar for two particular types. All we do is make a copy of bar's RHS with a particular coercion. Unlike notmrla class methods, that does not unlock any new optimisation opportunities in the specialised RHS.

TL;DR: narrow Note [Do not unbox class dictionaries] to ignore tuple classes and equality classes.

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