| iterIO uses mkTyCon for the simple reason that ((Typeable t, Typeable
| m) => Iter t m) is Typeable1 and there is no automatic way of deriving
| Typeable1.    

This email is triggered by a thread on Haskell Cafe about changes to the 
Typeable class
http://www.mail-archive.com/haskell-cafe@haskell.org/msg91830.html
It proposes a modification to the way Typeable is derived; and concludes with a 
question.

Simon


David Mazieres and others comment that you can't derive Typeable for types like 
this:
        data T f = MkT (f Int)
So he defines his own instance like this
[C]     instance Typable1 f => Typeable (T f) where
          typeOf = ...

So why can't GHC do this?  Well, here's what GHC does. Given a bog standard 
data type like Maybe
        data Maybe a = Nothing | Just a deriving( Typeable )
GHC generates this instance
[A]     instance Typeable1 Maybe where
           typeOf = ...
Remember that Typeable1 takes a type *constructor*, of kind (*->*), as its 
argument.

Now if we need (Typeable (Maybe Int)), GHC first uses an instance from the 
Typeable library:
[B]     instance (Typeable1 f, Typeable a) => Typeable (f a) where
          typeOf = ...

And now it uses the (Typeable1 Maybe) instance [A].  So it's kind of cool... 
the applications are decomposed by [B], leaving the tycon to [A].


But this doesn't work for T above.  We can't make (Typeable1 T) because T has 
kind ((*->*)->*), not (*->*) as Typeable1 requires.  Hence David defining his 
own instance.

GHC could do this too.  Indeed it could do so for Maybe too, thus:
        instance Typeable a => Typeable (Maybe a) where 
          typeOf = ...

But then, alas, we could not get (Typeable (T Maybe)), because [C] needs Maybe 
to be in Typeable1.

========== PROPOSAL ==============
So here is a compromise, which would at least do better than the current story:

        When deriving Typeable for a data type S of kind
                S :: k1 -> .. -> kn -> * -> ... -> *
        (where kn is not *, and there are M trailing * arguments),
        generate the instance
           instance (Typeable_x1 a1, ..., Typeable_xn an)
                => TypeableM (S a1 .. an)

That is, knock off all the trailing * args, and then generate an instance for 
the remaining stub. 

===================== EXAMPLE ============
Example from iterIO:

newtype Iter (t :: *) (m :: *->*) (a :: *)
   = Iter { runIter :: Chunk t -> IterR t m a }
   deriving( Typeable )

This should generate

        instance (Typeable t, Typeable1 m) => Typeable1 (Iter t m) 

where we knock off the trailing (a :: *) argument.

================== QUESTION =================
This approach is not beautiful.  It does not solve the underlying problem, 
which is a lack of kind polymorphism, but that is a battle for another day.  
Until that day, this alternative way of deriving Typeable would automate 
significantly more cases, I think.  Of course, it also makes it more 
complicated to explain when "deriving Typeable" will succeed.

Any opinions?  Does anyone care?

Simon


_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

Reply via email to