Skip to content

Fragile RULES in GHC.Float

Consider a method like

    class ... => RealFrac a where
       floor :: Integral b => a -> b

So floor :: forall a. RealFrac a => forall b. Integral b => a -> b. Notice the two dictionary arguments.

Now suppose we want to hand-write specialised code for (floor @Double d1 @Int d2). We used to have

   RULE "floor/Double->Int" floor = floorDoubleInt

where GHC.Float.RealFracMethods defines

   floorDoubleInt :: Double -> Int

This RULE in full is

   RULE "floor/Double->Int" forall d1 d2.
         floor @Double d1 @Int d2 = floorDoubleInt

But it's best not to write one rule for this entire step. I found cases (in nofib/readl/gamteb/Utils.hs, function fiRem) where we floated out the (floor @Double d1) part, so the above two-argument rule didn't fire. Instead the class-op rule fired. Boo!

Actually this only happens if we float out over-saturated applications (the floatOutOverSatApps flag in FloatOutSwitches, which currently we never do. So I don't think this patch will change a thing. But it makes GHC robust to floating out over-saturated applications, which I am experimenting with elsewhere, so I want to fix this infelicity first.

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