Search code examples
haskelloptimizationghc

Does GHC optimize the monoid operation over mempty?


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.


Solution

  • 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