GHC: Ticket #4220: EmptyDataDecls + DeriveFunctor == Panic!
http://ghc.haskell.org/trac/ghc/ticket/4220
<p>
I get "ghc: panic! (the 'impossible' happened)" from GHC 6.12.1 with a simple two-line program
</p>
<pre class="wiki"> {-# LANGUAGE EmptyDataDecls, DeriveFunctor #-}
data Void a deriving Functor
</pre><p>
Also <a class="ext-link" href="http://hpaste.org/fastcgi/hpaste.fcgi/view?id=28212"><span class="icon"></span>on hpaste</a>.
</p>
<p>
GHC says
</p>
<pre class="wiki"> ghc: panic! (the 'impossible' happened)
(GHC version 6.12.1 for i386-apple-darwin):
TcPat.checkArgs
</pre><p>
I asked on the #ghc IRC room and learned that
</p>
<blockquote class="citation">
<p>
ClaudiusMaximus: conal: ghc-6.12.3 here, same error. (GHC version 6.12.3 for x86_64-unknown-linux)
</p>
</blockquote>
en-usGHChttp://ghc.haskell.org/trac/ghc/chrome/site/ghc_logo.png
http://ghc.haskell.org/trac/ghc/ticket/4220
Trac 1.0.1conalSun, 25 Jul 2010 03:40:44 GMT
http://ghc.haskell.org/trac/ghc/ticket/4220#comment:1
http://ghc.haskell.org/trac/ghc/ticket/4220#comment:1
<p>
The following explicit instance works fine, though it's too bad we have to make the error case explicit, since Void can be covered exhaustively with no clauses.
</p>
<pre class="wiki">instance Functor Void where
fmap _ = error "Void fmap: no void value" -- so ghc won't complain
</pre>
TicketBMephMon, 26 Jul 2010 01:03:26 GMTcc, version changed
http://ghc.haskell.org/trac/ghc/ticket/4220#comment:2
http://ghc.haskell.org/trac/ghc/ticket/4220#comment:2
<ul>
<li><strong>cc</strong>
<em>black.meph@…</em> added
</li>
<li><strong>version</strong>
changed from <em>6.12.1</em> to <em>6.12.3</em>
</li>
</ul>
<p>
If you check the referenced hpaste, you'll see that it also occurs on Windows builds.
</p>
TicketBMephMon, 26 Jul 2010 01:04:17 GMTowner set
http://ghc.haskell.org/trac/ghc/ticket/4220#comment:3
http://ghc.haskell.org/trac/ghc/ticket/4220#comment:3
<ul>
<li><strong>owner</strong>
set to <em>conal</em>
</li>
</ul>
TicketsimonpjMon, 26 Jul 2010 09:42:42 GMT
http://ghc.haskell.org/trac/ghc/ticket/4220#comment:4
http://ghc.haskell.org/trac/ghc/ticket/4220#comment:4
<p>
Ah yes. I have a fix in my tree. Conal, did becoming the "owner" mean that you intended to submit a patch?
</p>
<p>
My fix generates a catch-all equation for fmap
</p>
<pre class="wiki">fmap _ a = unsafeCoerce# a
</pre><p>
in two cases:
</p>
<ul><li>When there are no constructors
</li><li>When there are any constructors that don't mention the "active" type variable at all
</li></ul><p>
The latter case is to catch a situation like this
</p>
<pre class="wiki"> data T a b = T1 b | T2 a | T3 a | T4 a | T5
</pre><p>
The "active" type variable is the last one in type, "b" in this case. Here it seems a waste to pattern-match on T2-T5 (as the current 6.12 does).
</p>
<p>
Better to say
</p>
<pre class="wiki">fmap f (T1 x) = T1 (f x)
fmap _ a = unsafeCoerce# a
</pre><p>
The coerce is necessary to change the type, of course.
</p>
<p>
Does that seem right?
</p>
<p>
There must be something similar for <tt>Foldable</tt> and <tt>Traversable</tt>, not just <tt>Functor</tt>, and we'd better fix them at the same time:
</p>
<ul><li>I believe the criterion is the same: that is, any data constructors whose argument types do not mention the active type variable can be treated uniformly with a no-op.
</li></ul><ul><li>I'm not sure what the code for a no-op for <tt>Foldable</tt> and <tt>Traversable</tt> are. Can someone say, please?
</li></ul><p>
Simon
</p>
TicketconalWed, 28 Jul 2010 16:03:53 GMTowner deleted
http://ghc.haskell.org/trac/ghc/ticket/4220#comment:5
http://ghc.haskell.org/trac/ghc/ticket/4220#comment:5
<ul>
<li><strong>owner</strong>
<em>conal</em> deleted
</li>
</ul>
TicketiglooSat, 31 Jul 2010 20:55:13 GMTowner, milestone set
http://ghc.haskell.org/trac/ghc/ticket/4220#comment:6
http://ghc.haskell.org/trac/ghc/ticket/4220#comment:6
<ul>
<li><strong>owner</strong>
set to <em>simonpj</em>
</li>
<li><strong>milestone</strong>
set to <em>6.14.1</em>
</li>
</ul>
TicketJulesBeanFri, 06 Aug 2010 08:32:04 GMTcc changed
http://ghc.haskell.org/trac/ghc/ticket/4220#comment:7
http://ghc.haskell.org/trac/ghc/ticket/4220#comment:7
<ul>
<li><strong>cc</strong>
<em>jules@…</em> added
</li>
</ul>
<p>
For <tt>Foldable</tt> it suffices to define <tt>foldMap</tt> :
</p>
<pre class="wiki">foldMap :: Monoid m => (a -> m) -> t a -> m
</pre><p>
If you "don't have" anything of type <tt>a</tt> either because it's an <a class="missing wiki">EmptyDataDecl?</a> or because it's a constructor which doesn't mention the type variable, then the only possible result is <tt>mempty</tt>.
</p>
<pre class="wiki">foldMap _ _ = mempty
</pre><p>
That suffices to define an instance, but for efficiency(?) you could add the other methods directly.
</p>
<pre class="wiki">fold :: Monoid m => t m -> m
fold _ = mempty
foldMap :: Monoid m => (a -> m) -> t a -> m
foldMap _ _ = mempty
foldr :: (a -> b -> b) -> b -> t a -> b
foldr _ start _ = start
foldl :: (a -> b -> a) -> a -> t b -> a
foldl _ start _ = start
foldr1 :: (a -> a -> a) -> t a -> a
foldr1 _ _ = error "Foldable.foldr1"
foldl1 :: (a -> a -> a) -> t a -> a
foldl1 _ _ = error "Foldable.foldl1"
</pre><p>
For <tt>Traversable</tt> it suffices to define <tt>traverse</tt>:
</p>
<pre class="wiki">traverse :: Applicative f => (a -> f b) -> t a -> f (t b)
</pre><p>
Similar reasoning - if you don't have any <tt>a</tt> then you can't apply the function given, and there can be no applicative effects to consider because no value <tt>f b</tt> can be constructed. So, rather like in the functor case, you do a constructor by constructor conversion, wrapped in <tt>pure</tt> for no effects.
</p>
<pre class="wiki">traverse _ (T2 a) = pure (T2 a) -- n.b. these two (T2 a) expressions are at a different type
</pre><p>
By the same process as for Functor you might choose to go for the under-the-hood more efficient <tt>pure . unsafeCoerce#</tt>, or alternatively you can "delegate" the efficiency hack to the Functor instance and use <tt>pure . fmap undefined</tt>.
</p>
<p>
Does that all sound reasonable?
</p>
TicketsimonpjThu, 12 Aug 2010 13:17:26 GMTstatus changed; testcase, resolution set
http://ghc.haskell.org/trac/ghc/ticket/4220#comment:8
http://ghc.haskell.org/trac/ghc/ticket/4220#comment:8
<ul>
<li><strong>status</strong>
changed from <em>new</em> to <em>closed</em>
</li>
<li><strong>testcase</strong>
set to <em>deriving/should_compile/T4220</em>
</li>
<li><strong>resolution</strong>
set to <em>fixed</em>
</li>
</ul>
<p>
In the end I did the simplest thing. Fixed by
</p>
<pre class="wiki">Thu Aug 12 14:13:19 BST 2010 simonpj@microsoft.com
* Fix Trac #4220
For deriving Functor, Foldable, Traversable with empty
data cons I just generate a null equation
f _ = error "urk"
There are probably more lurking (eg Enum) but this will do for now.
</pre><p>
Simon
</p>
Ticket