Haskell Type Names as Strings

2017-12-12
haskelltype-level

I will introduce a few different ways to convert a type, from the type itself or from a value of a type, to a string. Here are all of the language pragmas and imports we will need.

A type declaration we will use later.

A type without a constructor.

GHC allows us to use strings as types. Also known as Symbols. Symbols are useful when we calculate types and we want to pass some string data along, maybe as a file path or a route (servant does this), to another type. It is even possible to perform operations on the string at the type level. We may want to look at what the resulting string is by converting it to a value.

To work with types directly, and not the values of a particular type, we must use Proxy :: Proxy ... to capture the type and pass it to a function. This says we are referrencing a type, but not any particular value of a type. A constructor is not required. symbolVal converts the type level string to a value level string. If you want to pass a type to a function and run symbolVal on int, you must include KnownSymbol a => ... as a constraint.

Runtime : Symbol to String

Using symbolsVal, we can convert a type level list of type level strings to the value level.

Runtime : Type Proxy to String

Get the type name of non-symbols. If you want to pass a type to a function and run typeRep on in, you must include TypeRep a => ... as a constraint.

Get the type name of a value.

typeRep returns TypeRep for a Proxy of a type and typeOf returns TypeRep for a value of a type. show on a TypeRef. typeRepTyCon turns a TypeRep into a TyCon and allows us to extract more useful information.

Package name where Person is defined.

Module name where Person is defined.

Type level constructor.

Compile Time : Type to Symbol

Finally, there may be a case where you want to convert a type into Symbol while you are still compiling. For example, for a given type build a servant route base on the Symbol of the type. GHC does not provide a way to automatically convert a type to Symbol so we need to define our own type family to handle this using GHC.Generics. For any type that does not have a Generic instance, you must manually define what its Symbol is.

Now we can convert a type to a Symbol and the Symbol to a String.

Notes:

Run with stack runghc --package typelits-witnesses -- 2017-12-12-type-name-to-string.lhs.

References: