Version 4 (modified by dreixel, 3 years ago) (diff)


Kind-polymorphic Typeable

The page describes an improved implementation of the Typeable class, using polymorphic kinds. Technically it is straightforward, but it represents a non-backward-compatible change to a widely used library, so we need to make a plan for the transition.

Relevant tickets we could thereby fix: #5391, #5863.

Open question: what are the corresponding changes to Data.Data? See #4896,

The current Typeable class

The current Typeable class is:

class Typeable (a :: *) where
  typeOf :: a -> TypeRep

Because it is mono-kinded we also have

class Typeable1 (f :: *->*) where
  typeOf1 :: f a -> TypeRep

and so on up to Typeable7. It's a mess, and we cannot make Typeable at all for type constructors with higher kinds like

  Foo :: (* -> *) -> *

See #5391

The new Typeable class

Having polymorphic kinds lets us say this:

data Proxy t = Proxy

class Typeable t where
  typeRep :: Proxy t -> TypeRep

Notice that

  • Typeable and Proxy have polymorphic kinds:
      Proxy    :: forall k. k -> *
      Typeable :: forall k. k -> Constraint
  • The method is called typeRep rather than typeOf
  • 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 t may have any kind, so we can't say
      typeOf :: t -> TypeRep

Now we can give give 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 would always generate

instance Typable T where typeRep _ = ....

i.e. an instance of T itself, not applied to anything.


Iavor suggested:

class Typeable (a :: k) where
  typeRep :: TTypeRep a

newtype TTypeRep a = TR TypeRep

Is this perhaps better?

A change-over plan

In GHC 7.6:

  • Rename Data.Typeable to Data.OldTypeable and deprecate the whole module.
  • Define a new library Data.Typeable with the new definitions in them.
  • Include in Data.Typeable old methods for backward compatibility, but deprecate them:
    ttypeOf :: forall a. Typeable a => a -> TypeRep
    typeOf = typeRep (Proxy :: Proxy a)
    typeOf1 :: forall t (a :: *). Typeable t => t a -> TypeRep
    typeOf1 x = typeRep (Proxy :: Proxy t)
  • Make deriving( Typeable ) work with whatever Typeable class is in scope. So what it does will be determined by whether you say import Data.Typeable or import Data.OldTypeable.

I think that means that old programs will continue to work in GHC 7.6, provided

  • You did not mention Typeable1 etc explicitly
  • You used deriving( Typeable ) to write instances.

In GHC 7.8:

  • Remove Data.OldTypeable