Search code examples
haskelltemplate-haskelltype-level-computation

How to bring type information into value level in Haskell?


I'm looking for ways of way to bring type information into value level in Haskell.

One way I know to represent any type information as a value is the Language.Haskell.TH.Type. Is there any way to implement a function that takes Proxy a and returns Language.Haskell.TH.Type (or alternative type to represent any type) of the a type as follows?

If you have a better idea to bring type information as a value that does not use Language.Haskell.TH.Type, please tell me that, too.

import Data.Proxy (Proxy)
import Language.Haskell.TH (Type, TypeQ)

-- |
-- >>> amazing (Proxy :: Proxy Bool)
-- ConT GHC.Types.Bool
--
-- >>> amazing (Proxy :: Proxy [String])
-- AppT ListT (ConT GHC.Base.String)
amazing :: Proxy a -> Type
amazing p = undefined

-- |
-- Or if above is impossible, how about this?
amazingQ :: Proxy a -> TypeQ
amazingQ p = undefined

Solution

  • It boils down to finding what you want to do with that type information. In either case, the modules you will probably be looking at are Data.Typeable and Data.Data. At the center of these modules are the two typeclasses (deriveable via -XDeriveDataTypeable)

    class Typeable a where {...}
    class Typeable a => Data a where {..}
    

    As @chi mentions, the former of these lets you poke a type to find out information about it. That said there is the caveat that you need instances of Typeable for this to work (although you can start making orphan instances of these if you really need to...). In particular, there is typeRep:

    ghci> import Data.Typeable
    ghci> typeRep (Proxy :: Proxy (Either (Maybe [Integer]) ((), Bool, Int)))
    Either (Maybe [Integer]) ((), Bool, Int)
    

    However, if you ever decide you want to use the type information to try to lookup the value representations (ie. constructors) it has, you'll want to look at Data.Data.