Does GHC optimize the monoid operation over mempty?

97 Views Asked by At

If I write an instance of Monoid with a horrible complexity for its operation (<>), will GHC know that

mempty <> x = x
x <> mempty = x

and avoid computing (<>) ?

I'm also interested in how you got that information, and, if this optimization does not exits, whether this could be done or has been discussed previously.

2

There are 2 best solutions below

2
leftaroundabout On BEST ANSWER

Here's a sketch for how a rewrite rule can accomplish what you've layed out in your comment:

{-# LANGUAGE UnicodeSyntax #-}

module RewriteMempty where

data Big = Big String

instance Semigroup Big where
  Big s <> Big t = Big . reverse $ reverse s++reverse t
instance Monoid Big where
  mempty = Big ""

class Inflatable a where
  inflate :: a -> Big

instance Inflatable Double where
  inflate = Big . show . replicate 100000

{-# NOINLINE poppedBalloon #-}
poppedBalloon :: Big
poppedBalloon = mempty
{-# RULES "OmitPopped" ∀ x . poppedBalloon <> x = x #-}

instance Inflatable Int where
  {-# INLINE inflate #-}
  inflate _ = poppedBalloon

big :: Big
big = inflate (pi :: Double)

debig :: Big -> String
debig (Big s) = show $ length s

{-# SPECIALIZE busy :: Int -> String #-}

busy :: Inflatable a => a -> String
busy x = debig $ inflate x <> big
7
amalloy On

No, for several reasons. First, you don't have to write lawful Semigroup instances. x <> y = x is a valid definition as far as the compiler is concerned, and it has to generate code that matches the behavior you specify. So there can be no such optimization for every Semigroup.

GHC also can't in general know whether some value is equal to mempty or not, except by testing it, which it could only do given an Eq instance. But it's not going to go inserting implicit (==) tests around every Semigroup operation just to avoid calling your (<>) implementation. If you have a specific Semigroup type that you think will perform better if you check for mempty before doing the main work of (<>), you can insert that in the Semigroup instance yourself.