GHC: Ticket #6102: Subclass Specialization in Rewrite Rules
http://ghc.haskell.org/trac/ghc/ticket/6102
<p>
Rewrite rules can define a specialized version of a method for some specific datatype, but they cannot currently define a specialized version of a method for some specific superclass.
</p>
<pre class="wiki">class ClassOne a where
classOneOp :: a -> a
class ClassOne a => ClassTwo a where
classTwoOp :: a -> a
data ClassInstance = ...
instance ClassOne ClassInstance where
classOneOp = ...
specialFunc :: ClassInstance -> ClassInstance
specialFunc = ...
{-# RULES
"willcompile" forall i. classOneOp i = specialFunc
"wontcompile" forall i. classOneOp i = classTwoOp i
#-}
</pre><p>
Although we can specialize <em>classOneOp</em> for <em>ClassInstance</em>, we can't do so for those instances of <em>ClassOne</em> that are also instances of <em>ClassTwo</em>.
</p>
en-usGHChttp://ghc.haskell.org/trac/ghc/chrome/site/ghc_logo.png
http://ghc.haskell.org/trac/ghc/ticket/6102
Trac 1.0.9SamAnklesariaThu, 17 May 2012 02:29:09 GMTowner set
http://ghc.haskell.org/trac/ghc/ticket/6102#comment:1
http://ghc.haskell.org/trac/ghc/ticket/6102#comment:1
<ul>
<li><strong>owner</strong>
set to <em>SamAnklesaria</em>
</li>
</ul>
TicketsimonpjThu, 17 May 2012 11:04:37 GMTdifficulty set
http://ghc.haskell.org/trac/ghc/ticket/6102#comment:2
http://ghc.haskell.org/trac/ghc/ticket/6102#comment:2
<ul>
<li><strong>difficulty</strong>
set to <em>Unknown</em>
</li>
</ul>
<p>
Correct, and I see no way to avoid this. Consider
</p>
<pre class="wiki">foo :: ClassOne a => a -> a
foo x = classOneOp (classOneOp a)
</pre><p>
Imagine firing rule "wontcompile" on the source code. You'd get:
</p>
<pre class="wiki">foo :: ClassOne a => a -> a
foo x = classTwoOp (classTwoOp a)
</pre><p>
But that's ill-typed! <tt>classTwoOp</tt> needs <tt>(ClassTwo a)</tt> and that simply isn't available in <tt>foo</tt>.
</p>
<p>
However THIS should work:
</p>
<pre class="wiki">"wontcompile" forall i. classOneOp i = classTwoOp i :: ClassInstance
</pre><p>
Note the signature, so that the rule fires only when specialised to <tt>ClassInstance</tt>.
</p>
<p>
But it still doesn't:
</p>
<pre class="wiki">T6102.hs:19:45:
Could not deduce (ClassTwo ClassInstance)
arising from a use of `classTwoOp'
from the context (ClassOne ClassInstance)
bound by the RULE "wontcompile" at T6102.hs:19:1-73
Possible fix:
add an instance declaration for (ClassTwo ClassInstance)
In the expression: classTwoOp i :: ClassInstance
When checking the transformation rule "wontcompile"
</pre><p>
That's a bug. I'll look at it.
</p>
TicketsimonpjThu, 17 May 2012 13:54:21 GMTstatus changed; resolution set
http://ghc.haskell.org/trac/ghc/ticket/6102#comment:3
http://ghc.haskell.org/trac/ghc/ticket/6102#comment:3
<ul>
<li><strong>status</strong>
changed from <em>new</em> to <em>closed</em>
</li>
<li><strong>resolution</strong>
set to <em>invalid</em>
</li>
</ul>
<p>
Oh silly me. Of course <tt>ClassInstance</tt> is not an instance of <tt>ClassTwo</tt>. If you add such an instance all is well. Code below compiles fine
</p>
<pre class="wiki">module T6102 where
class ClassOne a where
classOneOp :: a -> a
class ClassOne a => ClassTwo a where
classTwoOp :: a -> a
data ClassInstance = A | B
instance ClassOne ClassInstance where
classOneOp _ = A
instance ClassTwo ClassInstance where
classTwoOp _ = B
specialFunc :: ClassInstance -> ClassInstance
specialFunc _ = A
{-# RULES
"willcompile" forall i. classOneOp i = specialFunc
"alsocompiles" forall i. classOneOp i = classTwoOp i :: ClassInstance
#-}
</pre><p>
So I'll close this.
</p>
TicketSamAnklesariaFri, 18 May 2012 20:25:49 GMT
http://ghc.haskell.org/trac/ghc/ticket/6102#comment:4
http://ghc.haskell.org/trac/ghc/ticket/6102#comment:4
<p>
I don't think I expressed the feature request very well. The idea was that rewriting would only occur when the types matched. "willcompile" will only change classOneOp to specialFunc when the result is a ClassInstance. Likewise, I was thinking it would be useful to have "wontcompile" only change classOne to classTwoOp when the result is shown to be an instance of ClassTwo.
In your example, one couldn't assume that the result of classOneOp (classOneOp a) was an instance of ClassTwo, and the rewrite wouldn't happen.
</p>
<p>
I don't know if this kind of behavior is possible, but it isn't something that would produce ill typed expressions.
</p>
TicketsimonpjMon, 21 May 2012 07:26:41 GMT
http://ghc.haskell.org/trac/ghc/ticket/6102#comment:5
http://ghc.haskell.org/trac/ghc/ticket/6102#comment:5
<p>
Replying to <a class="ticket" href="http://ghc.haskell.org/trac/ghc/ticket/6102#comment:4" title="Comment 4">SamAnklesaria</a>:
</p>
<blockquote class="citation">
<p>
Likewise, I was thinking it would be useful to have "wontcompile" only change classOne to classTwoOp when the result is shown to be an instance of ClassTwo.
</p>
</blockquote>
<p>
I'm afraid I don't know how to achieve that!
</p>
Ticket