|Version 10 (modified by 3 years ago) (diff),|
Typeablein GHC 7.8
The page describes an improved implementation of the
Typeable class, using polymorphic kinds, available from GHC 7.8. Technically it is straightforward, but it represents a non-backward-compatible change to a widely used library, so we had to make a plan for the transition.
Typeable class before 7.8
Before 7.8, the
Typeable class was as follows:
class Typeable (a :: *) where typeOf :: a -> TypeRep
Because it was mono-kinded we also had
class Typeable1 (f :: *->*) where typeOf1 :: f a -> TypeRep
and so on up to
Typeable7. It was a mess, and we couldn't make
Typeable at all for
type constructors with higher kinds like
Foo :: (* -> *) -> *
Typeable class, in GHC 7.8
Having polymorphic kinds lets us say this:
data Proxy t = Proxy class Typeable t where typeRep :: proxy t -> TypeRep
Typeablehas a polymorphic kind:
Typeable :: forall k. k -> Constraint
- The method is called
- One reason for the name change is that the argument is not a value of the type
t, but a value of type
(proxy t). We have to do this because
tmay have any kind, so we can't say
typeOf :: t -> TypeRep
- You can instantiate
proxyto whatever you want; one common choice is the poly-kinded
Proxy:: forall k. k -> *
Now the base library code can have kind-specific instances:
instance Typeable Int where typeRep _ = ... instance Typeable  where typeRep _ = ... instance (Typeable a, Typeable b) => Typeable (a b) where typeRep _ = ...
A use of
deriving( Typeable ) for a type constructor
T always generates
instance Typable T where typeRep _ = ....
i.e. an instance of
T itself, not applied to anything.
How to make your code compile again
If you have code involving
Typeable that fails to compile with 7.8, it might be due to the changes described above. Here's a few things to keep in mind in order to make your code compile again:
- Users can no longer giving manual instances of
Typeable; they must be derived.
- Manual instances were often written for datatypes with non kind-
*arguments. These can now be derived without problems. So if you had, for example:
data Fix f = In (f (Fix f)) instance (Typeable1 f) => Typeable (Fix f) where typeOf = ...you can now simply attach
- You can still use
typeOf1..7; they are now just (deprecated) type-specific versions of
typeRep. But keep in mind that they are no longer methods of a class, as the classes
Typeable1..7no longer exist.
- You can still use
Typeable1..7; they are now just (deprecated) type synonyms for
Typeable, fixing the kind of their argument. But keep in mind that they are no longer classes, just type synonyms.
- If all else fails, you could just try replacing your
import Data.OldTypeable. But keep in mind that
OldTypeableis distinct, and incompatible with the new
- If you want code that compiles with multiple versions of GHC, you should use CPP. The tagged package on Hackage is a good example of how to achieve this.
A change-over plan
In GHC 7.8:
Data.OldTypeableand deprecate the whole module.
- Define a new library
Data.Typeablewith the new definitions in them.
- Include in
Data.Typeableold methods for backward compatibility, but deprecate them:
typeOf :: forall a. Typeable a => a -> TypeRep typeOf _ = typeRep (Proxy :: Proxy a) typeOf1 :: forall t (a :: *). Typeable t => t a -> TypeRep typeOf1 _ = typeRep (Proxy :: Proxy t) type Typeable1 (a :: * -> *) = Typeable a type Typeable2 (a :: * -> * -> *) = Typeable a
deriving( Typeable )work with whatever
Typeableclass is in scope. So what it does will be determined by whether you say
In GHC 7.10:
Open question: what are the corresponding changes to
Data.Data? See #4896.