[Haskell-cafe] rewrite rules to specialize function according to type class?

Max Bolingbroke batterseapower at hotmail.com
Tue Feb 15 10:07:49 CET 2011

2011/2/15 Gábor Lehel <illissius at gmail.com>:
> This is a semi-related question I've been meaning to ask at some
> point: I suppose this also means it's not possible to write a class,
> write some rules for the class, and then have the rules be applied to
> every instance? (I.e. you'd have to write them separately for each?)

This does work, because it doesn't require the simplifier to lookup up
class instances. However, it's a bit fragile. Here is an example:

class Foo a where
  foo :: a -> a
  bar :: a -> a
  foo_bar :: a -> a

{-# RULES "foo/bar" forall x. foo (bar x) = foo_bar x #-}

instance Foo Bool where
    foo = not
    bar = not
    foo_bar = not

instance Foo Int where
    foo = (+1)
    bar x = x - 1
    foo_bar = (+2)

{-# NOINLINE foo_barish #-}
foo_barish :: Foo a => a -> a
foo_barish x = foo (bar x)

main = do
    print $ foo (bar False)       -- False if rule not applied, True otherwise
    print $ foo (bar (2 :: Int))  -- 2 if rule not applied, 4, otherwise
    print $ foo_barish False      -- False if rule not applied, True otherwise
    print $ foo_barish (2 :: Int) -- 2 if rule not applied, 4, otherwise

With GHC 7, the RULE successfully rewrites the foo.bar composition
within foo_barish to use foo_bar. However, it fails to rewrite the two
foo.bar compositions inlined directly in main. Thus the output is:


The reason it cannot rewrite the calls in main is (I think) because
the foo/bar class selectors are inlined before the rule matcher gets
to spot them. By using NOINLINE on foo_barish, and ensuring that
foo_barish is overloaded, we prevent the simplifier from doing this
inlining and hence allow the rule to fire.

What is more interesting is that I can't get the foo (bar x) rule to
fire on the occurrences within main even if I add NOINLINE pragmas to
the foo/bar names in both the class and instance declarations.
Personally I would expect writing NOINLINE on the class declaration
would prevent the class selector being inlined, allowing the rule to
fire, but that is not happening for some reason.

Perhaps this is worth a bug report on the GHC trac? It would at least
give it a chance of being fixed.


More information about the Haskell-Cafe mailing list