packages feed

compaREST-0.1.0.0: src/Data/HList.hs

module Data.HList
  ( Has,
    HasAll,
    getH,
    HList (..),
    singletonH,
    ReassembleHList,
    reassemble,
  )
where

import Data.Kind
import GHC.TypeLits

data HList (xs :: [Type]) where
  HNil :: HList '[]
  HCons :: x -> HList xs -> HList (x ': xs)

infixr 5 `HCons`

type family HasAll xs ys :: Constraint where
  HasAll '[] _ = ()
  HasAll (x ': xs) ys = (Has x ys, HasAll xs ys)

type Has x xs = Has' x xs (HeadEq x xs)

type family HeadEq x xs where
  HeadEq x (x ': _) = 'True
  HeadEq _ _ = 'False

class t ~ HeadEq x xs => Has' (x :: Type) (xs :: [Type]) (t :: Bool) where
  getH :: HList xs -> x

instance Has' x (x ': xs) 'True where
  getH (HCons x _) = x
  {-# INLINE getH #-}

instance (Has' x xs t, HeadEq x (y : xs) ~ 'False) => Has' x (y ': xs) 'False where
  getH (HCons _ xs) = getH xs
  {-# INLINE getH #-}

instance
  TypeError ( 'ShowType x ':<>: 'Text " is not a part of the list.") =>
  Has' x '[] 'False
  where
  getH HNil = undefined
  {-# INLINE getH #-}

singletonH :: a -> HList '[a]
singletonH a = a `HCons` HNil
{-# INLINE singletonH #-}

instance Eq (HList '[]) where
  HNil == HNil = True

instance (Eq x, Eq (HList xs)) => Eq (HList (x ': xs)) where
  (HCons x xs) == (HCons y ys) = x == y && xs == ys

type family (==) a b :: Bool where
  a == a = 'True
  _ == _ = 'False

type ReassembleHList xs ys = ReassembleHList' xs ys (xs == ys)

class f ~ (xs == ys) => ReassembleHList' xs ys f where
  reassemble :: HList xs -> HList ys

instance ReassembleHList' xs xs 'True where
  reassemble = id
  {-# INLINE reassemble #-}

instance ReassembleHList' (x ': xs) '[] 'False where
  reassemble _ = HNil
  {-# INLINE reassemble #-}

instance
  (Has y xs, ReassembleHList' xs ys f, (xs == (y ': ys)) ~ 'False) =>
  ReassembleHList' xs (y ': ys) 'False
  where
  reassemble xs = getH @y xs `HCons` reassemble xs
  {-# INLINE reassemble #-}