Data.Dynamic: Any vs existential

Simon Peyton Jones simonpj at
Mon Mar 10 20:49:14 UTC 2014

It's certainly true that, with the current setup, a monomorphic instance will look like

instance Typeable Foo where

  typeRep# = \_ -> (...something...) :: TypeRep

and the optimiser will float the (...something...) to top level.  But this is an optimisation, not true by construction.  For example, a non-top-level instance might look like

instance (Typeable a, Typeable b) => Typeable (a b) where

  typeRep# = \_ -> mkAppTy (typeRep# (undefined::Proxy a))

                           (typeRep# (undefined :: Proxy b))

And that in turn will become

$dfTyApp = /\a b. \(d1::Typeable a) (d2::Typeable b).

           \_ -> mkAppTy (d1 a) (d2 b)

(I'm missing out some newtypes etc.)  Now, will the (d1 a) and (d2 b) be floated outside the \_?  Not so certain.  It depends on the let-floater.

The good thing about the Tagged stuff is that there is no lambda in the first place, so the issue doesn't arise.

It's ok if the programming interface is less easy to use; Data.Typeable.typeOf is already a function, not a method.  The method is called typeRep#, and is internal.

So I think you can go ahead and improve the design. But it's clearly a library-committee decision; I'll just do what you say.


From: Libraries [mailto:libraries-bounces at] On Behalf Of Dan Doel
Sent: 10 March 2014 18:02
To: Roman Cheplyaka
Cc: Haskell Libraries
Subject: Re: Data.Dynamic: Any vs existential

On Mon, Mar 10, 2014 at 6:35 AM, Roman Cheplyaka <roma at<mailto:roma at>> wrote:
Ok, one reason is that the TypeRep won't be cached in the Dynamic value.
Even in GHC 7.8 Typeable is defined as

  class Typeable a where
    typeRep# :: Proxy# a -> TypeRep

instead of

  class Typeable a where
    typeRep :: Tagged a TypeRep

Why? Is this an oversight?

I talked with Ed about this, and he noted that this might be a false problem. Certainly, the Proxy# is never actually used, so as long as the generated instances are of the form:
    typeRep# = let tr = ... in \_ -> tr

the TypeReps are shared, and are at most a bit of indirection away. Also, how different are (Tagged tr :: Tagged a TypeRep) and ((\_ -> tr) :: Proxy# a -> TypeRep) at a low level? I know the constructor of the former disappears in core, but don't know what specifically happens with 0-width fields like Proxy#. Is the latter slightly less efficient? If so, can the optimizer eliminate the difference for cases like this?
-- Dan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the Libraries mailing list