11

I want to write a function with this type signature:

getTypeRep :: Typeable a => t a -> TypeRep

where the TypeRep will be the type representation for a, not for t a. That is, the compiler should automatically return the correct type representation at any call sites [to getTypeRep], which will have concrete types for a.

To add some context, I want to create a "Dynamic type" data type, with the twist that it will remember the top-level type, but not its parameter. For example, I want to turn MyClass a into Dynamic MyClass, and the above function will be used to create instances of Dynamic MyClass that store a representation of the type parameter a.

Don Stewart
  • 137,316
  • 36
  • 365
  • 468
gatoatigrado
  • 16,580
  • 18
  • 81
  • 143

3 Answers3

9

Well, how about using scoped type variables to select the inner component:

{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE ScopedTypeVariables #-}

import Data.Dynamic
import Data.Typeable

getTypeRep :: forall t a . Typeable a => t a -> TypeRep
getTypeRep _ = typeOf (undefined :: a)

Works for me:

*Main> getTypeRep (Just ())
()
*Main> getTypeRep (Just 7)
Integer
*Main> getTypeRep ([True])
Bool

Interesting design.

Don Stewart
  • 137,316
  • 36
  • 365
  • 468
8

On a tangential note to Don's solution, notice that code rarely require ScopedTypeVariables. It just makes the solution cleaner (but less portable). The solution without scoped types is:

{-# LANGUAGE ExplicitForAll #-}
import Data.Typeable

helper :: t a -> a
helper _ = undefined

getTypeRep :: forall t a. Typeable a => t a -> TypeRep
getTypeRep = typeOf . helper
Thomas M. DuBuisson
  • 64,245
  • 7
  • 109
  • 166
0

This function (now) exists in Data.Typeable typeRep

glguy
  • 1,090
  • 7
  • 8