deriving Enum fails for data instances
The following sample module does not compile:
{-# LANGUAGE TypeFamilies #-}
module Foo where
data family Foo a
data instance Foo Int
= A | B
deriving (Enum)
GHC gives 5 error messages, all to line 8 (the deriving clause), in terms of some internal representations of variables and types. I think that an error message should not be of this kind even if the code really contains an error. But here I even do not understand why the code should not be valid. In the case of deriving Eq, Ord, Bounded or Show for the same Foo Int, everything works fine; and also, old good instance declaration instead of deriving gives a normally working code. (Analogous errors are produced when deriving Ix.)
Here is the output of GHCi -v in the case of the above module (GHC gives a similar one):
Prelude> :l Foo
*** Chasing dependencies:
Chasing modules from:
Stable obj: []
Stable BCO: []
unload: retaining objs []
unload: retaining bcos []
Ready for upsweep []
Upsweep completely successful.
*** Deleting temp files:
Deleting:
*** Chasing dependencies:
Chasing modules from: *Foo.hs
Stable obj: []
Stable BCO: []
unload: retaining objs []
unload: retaining bcos []
Ready for upsweep
[NONREC
ModSummary {
ms_hs_date = Mon Aug 2 14:30:44 UTC 2010
ms_mod = main:Foo,
ms_imps = []
ms_srcimps = []
}]
compile: input file Foo.hs
*** Checking old interface for main:Foo:
[1 of 1] Compiling Foo ( Foo.hs, interpreted )
*** Parser:
*** Renamer/typechecker:
Foo.hs:8:12:
Couldn't match expected type `Foo Int'
against inferred type `Foo.R:FooInt'
NB: `Foo' is a type function
In the expression: Foo.$tag2con_R:FooInt ((+) (GHC.Types.I# a#) 1)
In the expression:
if (==) Foo.$maxtag_R:FooInt (GHC.Types.I# a#) then
error
"succ{R:FooInt}: tried to take `succ' of last tag in enumeration"
else
Foo.$tag2con_R:FooInt ((+) (GHC.Types.I# a#) 1)
In a case alternative:
a#
-> if (==) Foo.$maxtag_R:FooInt (GHC.Types.I# a#) then
error
"succ{R:FooInt}: tried to take `succ' of last tag in enumeration"
else
Foo.$tag2con_R:FooInt ((+) (GHC.Types.I# a#) 1)
Foo.hs:8:12:
Couldn't match expected type `Foo Int'
against inferred type `Foo.R:FooInt'
NB: `Foo' is a type function
In the expression: Foo.$tag2con_R:FooInt ((+) (GHC.Types.I# a#) -1)
In the expression:
if (==) 0 (GHC.Types.I# a#) then
error
"pred{R:FooInt}: tried to take `pred' of first tag in enumeration"
else
Foo.$tag2con_R:FooInt ((+) (GHC.Types.I# a#) -1)
In a case alternative:
a#
-> if (==) 0 (GHC.Types.I# a#) then
error
"pred{R:FooInt}: tried to take `pred' of first tag in enumeration"
else
Foo.$tag2con_R:FooInt ((+) (GHC.Types.I# a#) -1)
Foo.hs:8:12:
Couldn't match expected type `Foo Int'
against inferred type `Foo.R:FooInt'
NB: `Foo' is a type function
In the expression: Foo.$tag2con_R:FooInt a
In the expression:
if (&&) ((>=) a 0) ((<=) a Foo.$maxtag_R:FooInt) then
Foo.$tag2con_R:FooInt a
else
error
((++)
"toEnum{R:FooInt}: tag ("
(showsPrec
0
a
((++)
") is outside of enumeration's range (0,"
(showsPrec 0 Foo.$maxtag_R:FooInt ")"))))
In the definition of `toEnum':
toEnum a = if (&&) ((>=) a 0) ((<=) a Foo.$maxtag_R:FooInt) then
Foo.$tag2con_R:FooInt a
else
error
((++)
"toEnum{R:FooInt}: tag ("
(showsPrec
0
a
((++)
") is outside of enumeration's range (0,"
(showsPrec 0 Foo.$maxtag_R:FooInt ")"))))
Foo.hs:8:12:
Couldn't match expected type `Foo Int'
against inferred type `Foo.R:FooInt'
NB: `Foo' is a type function
In the first argument of `map', namely `Foo.$tag2con_R:FooInt'
In the expression:
map
Foo.$tag2con_R:FooInt
(enumFromTo (GHC.Types.I# a#) Foo.$maxtag_R:FooInt)
In a case alternative:
a#
-> map
Foo.$tag2con_R:FooInt
(enumFromTo (GHC.Types.I# a#) Foo.$maxtag_R:FooInt)
Foo.hs:8:12:
Couldn't match expected type `Foo Int'
against inferred type `Foo.R:FooInt'
NB: `Foo' is a type function
In the first argument of `map', namely `Foo.$tag2con_R:FooInt'
In the expression:
map
Foo.$tag2con_R:FooInt
(enumFromThenTo
(GHC.Types.I# a#)
(GHC.Types.I# b#)
(if (>) (GHC.Types.I# a#) (GHC.Types.I# b#) then
0
else
Foo.$maxtag_R:FooInt))
In a case alternative:
b#
-> map
Foo.$tag2con_R:FooInt
(enumFromThenTo
(GHC.Types.I# a#)
(GHC.Types.I# b#)
(if (>) (GHC.Types.I# a#) (GHC.Types.I# b#) then
0
else
Foo.$maxtag_R:FooInt))
*** Deleting temp files:
Deleting:
Upsweep partially successful.
*** Deleting temp files:
Deleting:
Failed, modules loaded: none.
Making deriving stand-alone does not help (the error messages would be more or less similar). It seems that the automatically derived code for methods is buggy and does not type-check.
Using GADTs also does not help, but the feedback is different. In the case of GADTs, (stand-alone) deriving does not work for other type classes either. For example, if the module is
{-# LANGUAGE GADTs, StandaloneDeriving, FlexibleInstances #-}
module Foo where
data Foo a where
A :: Foo Int
B :: Foo Int
deriving instance (Eq (Foo Int))
then GHCi says the following:
Foo.hs:1:0:
GADT pattern match in non-rigid context for `A'
Probable solution: add a type signature for `Foo.$con2tag_Foo'
In the pattern: A
In the definition of `Foo.$con2tag_Foo': Foo.$con2tag_Foo A = 0#
Note the location of the error according to the message! Anyway, after deleting the stand-alone deriving, GHCi is satisfied. By the way, :i A then gives:
data Foo a where
A :: (a ~ Int) => Foo Int
...
However, :t A gives:
A :: Foo Int
So, is the type system of GHC ambiguous? Why are the types given by :i and :t different?
Trac metadata
Trac field | Value |
---|---|
Version | 6.12.3 |
Type | Bug |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | Compiler (Type checker) |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | |
Architecture |