Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rewrite rules not firing for rules matching multiple instance methods

Tags:

haskell

As far as I can tell I wouldn't think it would make any difference that id1 and id2 are from a type class and id1' and id2' are not. I am running "ghc Rewrite" with the latest Haskell Platform (with both GHC version 7.0.4 and now 7.4.1 too), and I expect to1 to also fire.

$ ghc Rewrite
[1 of 1] Compiling RewriteProblems  ( Rewrite.hs, Rewrite.o )
Rule fired: rewrite/ez'
Rule fired: rewrite/to1'
Rule fired: rewrite/ez
Rule fired: rewrite/ez
Rule fired: Class op id2
Rule fired: Class op id2

the example:

{-# OPTIONS_GHC -O -ddump-rule-firings #-}
module RewriteProblems where

{-# RULES
"rewrite/ez"    forall a. id1 a = RDUnit
"rewrite/to1"   forall a. id2 (id2 a) = id1 a
"rewrite/ez'"   forall a. id1' a = RDUnit
"rewrite/to1'"  forall a. id2' (id2' a) = id1 a
   #-}

class Ider a where
    id1 :: a -> a
    id2 :: a -> a

data RewriteD = RDUnit

instance Ider RewriteD where
    {-# INLINE[1] id1 #-}
    {-# INLINE[1] id2 #-}
    id1 a = RDUnit
    id2 a = RDUnit

testThing1 :: RewriteD
testThing1 = id1 RDUnit

testThing2 :: RewriteD
testThing2 = id2 (id2 RDUnit)

testThing1' :: RewriteD
testThing1' = id1' RDUnit

testThing2' :: RewriteD
testThing2' = id2' (id2' RDUnit)

{-# INLINE[1] id1' #-}
{-# INLINE[1] id2' #-}
id1' :: RewriteD -> RewriteD
id2' :: RewriteD -> RewriteD
id1' a = RDUnit
id2' a = RDUnit
like image 728
Akh Avatar asked Mar 21 '12 19:03

Akh


1 Answers

(several edits made throughout post with updated information)

In your output, notice the lines Rule fired: Class op id2. These are rules automatically created by GHC for type class instances. This rule is firing first, so your own rule never gets a chance to match. If you compile with "-ddump-simpl-iterations", you can check that the Class op rule fires in the first phase, after which your "to1" rule will never match.

Here's a bit of a workaround. First comment out testThing1, testThing1', and testThing2' so only testThing2 is compiled. This is the only function where "rewrite/to1" can fire, so it isolates the test case you're looking at. Next add another rule of the form:

"rewrite/to_id2'"   forall a. id2 a = id2' a

and you'll see this output:

$ ghc -c foo.hs
Rule fired: rewrite/to_id2'
Rule fired: rewrite/to_id2'
Rule fired: rewrite/to1'
Rule fired: rewrite/ez

The new rule is now firing instead of the class op, which allows rewrite/to1' to simplify the expression. Interestingly, it doesn't matter if the new rule appears above or below rewrite/to1 in the list of RULES.

I don't know why your id2 (id2 a) rule isn't matching whereas id2 a does. It looks like it should match (according to -dverbose-core2core), but it isn't. I still suspect a GHC precedence bug of some type, although I also see the same behavior with ghc-7.4.1 so it isn't 4397.

like image 107
John L Avatar answered Oct 18 '22 07:10

John L