Type Level Heterogeneous List


HList is a well designed package for type level heterogeneous lists. We will take a look at the main declaration to get more familiar with type level programmin in Haskell.

Promote data types to to kind level. We want to use [] at the type level to operate over a list of types that we use to calculate the type signature.

{-# LANGUAGE DataKinds          #-}

Allow multiparameter typeclass instances instance C (Either a String) where ....

{-# LANGUAGE FlexibleContexts   #-}

Allow typeclass instances for nested types instance C (Maybe Int) where ....

{-# LANGUAGE FlexibleInstances  #-}

Allow deriving instance separated from the type declaration. It can be in the same file or another file.

{-# LANGUAGE StandaloneDeriving #-}

Allow indexed and data type families. The instances of data families can be data types and newtypes.

{-# LANGUAGE TypeFamilies       #-}

Allow the use and definition of types with operator names.

{-# LANGUAGE TypeOperators      #-}

HList is a list of inhabited types. They must be of kind *. HNil is an empty list of types. HCons is a constructor to concatentate to types.

data family HList (l :: [*])
data instance HList '[] = HNil
data instance HList (x ': xs) = x `HCons` HList xs

With deriving instance, Eq and Ord are straightforward.

deriving instance Eq (HList '[])
deriving instance (Eq x, Eq (HList xs)) => Eq (HList (x ': xs))

deriving instance Ord (HList '[])
deriving instance (Ord x, Ord (HList xs)) => Ord (HList (x ': xs))

Finally, we can iterate over the types to create an instance of Show and run a simple example.

instance Show (HList '[]) where
  show _ = "H[]"

instance (Show e, Show (HList l)) => Show (HList (e ': l)) where
  show (HCons x l) = 
    let 'H':'[':s = show l
    in "H[" ++ show x ++
         (if s == "]" then s else "," ++ s)
infixr 2 `HCons`

foo :: HList '[Char, String, Double]
foo = 'Z' `HCons` "Zebra" `HCons` 2.5 `HCons` HNil

main :: IO ()
main = print foo