GHC: Ticket #7080: Make RULES and SPECIALISE more consistent
http://ghc.haskell.org/trac/ghc/ticket/7080
<p>
This <a class="ext-link" href="http://www.haskell.org/pipermail/glasgow-haskell-users/2012-July/022580.html"><span class="icon"></span>glasgow-haskell-users email thread</a> describes the inconsistency between RULES and SPECIALISE pragmas. Consider
</p>
<pre class="wiki">module Test where
import Data.Monoid
import Control.Monad.Writer.Strict
f :: Monad m => a -> m a
f = return
g :: Monoid w => a -> Writer w a
g = return
{-# RULES "f->g" f = g #-}
{-# SPECIALISE f :: Monoid w => a -> Writer w a #-}
</pre><p>
Here, the SPECIALISE pragma is accepted, but the RULE is rejected thus:
</p>
<pre class="wiki"> Could not deduce (Monoid w) arising from a use of `g'
from the context (Monad (WriterT w Identity))
bound by the RULE "f->g" at Foo.hs:14:3-14
Possible fix: add (Monoid w) to the context of the RULE "f->g"
In the expression: g
When checking the transformation rule "f->g"
</pre><p>
Rejecting the RULE is quite right. On the LHS you have an application
</p>
<pre class="wiki"> f (WriterT w Identity) d
where d :: Monad (WriterT w Identity)
</pre><p>
Recall that <tt>Writer w = WriterT w Identity</tt>. For the rewrite to work you have to rewrite this to
</p>
<pre class="wiki"> g w d'
where
d' :: Monoid w
</pre><p>
Well, how can you get a <tt>Monoid w</tt> dictionary from a <tt>Monad (WriterT w Identity)</tt>?
</p>
<p>
I was surprised that the SPECIALISE pragma worked, but here's what it does (you can see with -ddump-rules):
</p>
<pre class="wiki">==================== Tidy Core rules ==================== "SPEC Foo.f" [ALWAYS]
forall (@ a) (@ w) ($dMonoid :: Data.Monoid.Monoid w).
Foo.f @ a
@ (Control.Monad.Trans.Writer.Strict.WriterT
w Data.Functor.Identity.Identity)
(Control.Monad.Trans.Writer.Strict.$fMonadWriterT
@ w
@ Data.Functor.Identity.Identity
$dMonoid
Data.Functor.Identity.$fMonadIdentity)
= Foo.f_f @ a @ w $dMonoid
</pre><p>
Ah! This rule will only match if the LHS is exactly
</p>
<pre class="wiki">f (WriterT w Identity) ($fMonadWriterT w Identity dm $fMonadIdentity)
</pre><p>
So it's a nested pattern match. That makes the LHS match less often; namely only when the dictionary argument to <tt>f</tt> is an application of <tt>$fMonadWriterT</tt>, the function that arises from the instance decl
</p>
<pre class="wiki"> instance (Monoid w, Monad m) => Monad (WriterT w m) where
</pre><p>
In exchange for matching less often, we now do get access to the <tt>(Monoid w)</tt> argument.
</p>
<p>
It is odd that this is inconsistent. Here is why. For a RULE, we must have a way to rewrite the LHS to an arbitrarily complicated RHS. For a SPECIALISE pragma
</p>
<pre class="wiki"> SPECIALISE f :: spec_ty
where f's type is
f :: poly_ty
</pre><p>
we simply ask whether <tt>poly_ty</tt> is more polymorphic than <tt>spec_ty</tt>; that is, whether <tt>f</tt> can appear in a context requiring a value of type <tt>spec_ty</tt>. If so, we see what arguments <tt>f</tt> would need to do that, and that's the LHS pattern.
</p>
<p>
But
</p>
<ul><li>It's odd that the behaviour is inconsistent
</li><li>The SPECIALISE rule is pretty fragile, beause it'll only match if the argument dictionary is constructed exactly as shown.
</li></ul><p>
It's not clear to me what, if anything, to do about this, but this ticket records the issue.
</p>
en-usGHChttp://ghc.haskell.org/trac/ghc/chrome/site/ghc_logo.png
http://ghc.haskell.org/trac/ghc/ticket/7080
Trac 1.0.1akioWed, 24 Apr 2013 04:23:53 GMTcc set
http://ghc.haskell.org/trac/ghc/ticket/7080#comment:1
http://ghc.haskell.org/trac/ghc/ticket/7080#comment:1
<ul>
<li><strong>cc</strong>
<em>tkn.akio@…</em> added
</li>
</ul>
<p>
I experienced a situation where I wanted to write rules like this. I think it would be very useful if the rule was accepted, and worked by finding whatever (Monoid w) dictionary that is in scope. But perhaps I am asking too much of the simplifier?
</p>
Ticket