5.3 Heterogeneous lists

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}

module Chapter05_1 () where

import Data.Kind (Constraint, Type)

data HList (ts :: [Type]) where
  HNil :: HList '[]
  (:#) :: t -> HList ts -> HList (t ': ts)
infixr 5 :#

type family All (c :: Type -> Constraint) (ts :: [Type]) :: Constraint where
  All c '[] = ()
  All c (t ': ts) = (c t, All c ts)

data HList' (ts :: [Type]) where
  HNil' :: HList' '[]
  (:#:) :: t -> HList' ts -> HList' (t ': ts)
infixr 5 :#:

instance (All Show ts) => Show (HList' ts) where
  show HNil' = ""
  show (a :#: HNil') = show a
  show (a :#: as) = show a <> ", " <> show as

f :: HList ts -> HList' ts
f hs = g hs HNil'
 where
  g :: HList ps -> HList' ps' -> HList' ps
  g HNil HNil' = HNil'
  g (a :# as) _ = a :#: g as HNil'
  g HNil _ = HNil'

instance (All Show ts) => Show (HList ts) where
  show ps = "[ " <> (show . f) ps <> "]"

p2 :: HList '[[Char], Bool, Integer, Bool]
p2 = "Hou" :# False :# 3 :# True :# HNil

-- >>>p2
-- [ "Hou", False, 3, True]