The module TypeRep exposes the representation becauese a few other modules (Type, TcType, Unify, etc) work directly on its representation. However, you should not lightly pattern-match on Type; it is meant to be an abstract type. Instead, try to use functions defined by Type, TcType etc.

where liftedTypeKindTyCon is a built-in PrimTyCon. The arrow type
constructor is used as the arrow kind constructor, e.g. the kind * ->*
is represented internally as

FunTy liftedTypeKind liftedTypeKind

It's easy to extract the kind of a type, or the sort of a kind:

typeKind :: Type -> Kind

The "sort" of a kind is always one of the
sorts: TY (for kinds that classify normal types) or CO (for kinds that
classify coercion evidence). The coercion kind, T1 :=: T2, is
represented by PredTy (EqPred T1 T2).

Type variables

Type variables are represented by the TyVar constructor of the data type Var.

Type variables range over both types (possibly of higher kind) or coercions. You could tell the differnece between these two by taking the typeKind of the kind of the type variable, adn seeing if you have sort TY or CO, but for efficiency the TyVar keeps a boolean flag, and offes a function:

isCoercionVar :: TyVar -> Bool

Classifying types

GHC uses the following nomenclature for types:

Unboxed

a type is unboxed iff its representation is other than a pointer. Unboxed types are also unlifted.

Lifted

a type is lifted iff it has bottom as an element. Closures always have lifted types: i.e. any let-bound identifier in Core must have a lifted type. Operationally, a lifted object is one that can be entered. Only lifted types may be unified with a type variable.

Data

A type declared with data. Also boxed tuples.

Algebraic

an algebraic data type is a data type with one or more constructors, whether declared with data or newtype. An algebraic type is one that can be deconstructed with a case expression. "Algebraic" is NOT the same as "lifted", because unboxed tuples count as "algebraic".

Primitive: a type is primitive iff it is a built-in type that can't be expressed in Haskell.

Currently, all primitive types are unlifted, but that's not necessarily the case. (E.g. Int could be primitive.)

Some primitive types are unboxed, such as Int#, whereas some are boxed but unlifted (such as ByteArray#). The only primitive types that we classify as algebraic are the unboxed tuples.