{-# LANGUAGE DataKinds #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE StandaloneDeriving #-} -- | Heterogeneous list utils module Haskus.Utils.HList ( HList (..) , hHead , hTail , hLength , hAppend , HFoldr' (..) , HFoldl' (..) , HTuple' (..) , Apply (..) , HZipList , hZipList , HFoldr , hFoldr , HFoldl , hFoldl , HReverse (..) ) where import Haskus.Utils.Tuple import Haskus.Utils.Types import Haskus.Utils.Types.List -- | Heterogeneous list data family HList (l :: [*]) data instance HList '[] = HNil data instance HList (x ': xs) = x `HCons` HList xs infixr 2 `HCons` 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)) 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) -- | Head hHead :: HList (e ': l) -> e hHead (HCons x _) = x -- | Tail hTail :: HList (e ': l) -> HList l hTail (HCons _ l) = l -- | Length hLength :: forall xs. (KnownNat (Length xs)) => HList xs -> Word hLength _ = natValue' @(Length xs) class HAppendList l1 l2 where hAppend :: HList l1 -> HList l2 -> HList (Concat l1 l2) instance HAppendList '[] l2 where hAppend HNil l = l instance HAppendList l l' => HAppendList (x ': l) l' where hAppend (HCons x l) l' = HCons x (hAppend l l') -- | Apply the function identified by the data type f from type a to type b. class Apply f a b where apply :: f -> a -> b -------------------------------------- -- Folding -------------------------------------- class HFoldr f v (l :: [*]) r where hFoldr :: f -> v -> HList l -> r instance (v ~ v') => HFoldr f v '[] v' where hFoldr _ v _ = v instance ( Apply f (e, r) r' , HFoldr f v l r ) => HFoldr f v (e ': l) r' where hFoldr f v (HCons x l) = apply f (x, hFoldr f v l :: r) -- | Like HFoldr but only use types, not values! -- -- It allows us to foldr over a list of types, without any associated hlist of -- values. class HFoldr' f v (l :: [*]) r where hFoldr' :: f -> v -> HList l -> r instance (v ~ v') => HFoldr' f v '[] v' where hFoldr' _ v _ = v instance ( Apply f (e, r) r' , HFoldr' f v l r ) => HFoldr' f v (e ': l) r' where -- compared to hFoldr, we pass undefined values instead of the values -- supposedly in the list (we don't have a real list associated to HList l) hFoldr' f v _ = apply f (undefined :: e, hFoldr' f v (undefined :: HList l) :: r) class HFoldl f (z :: *) xs (r :: *) where hFoldl :: f -> z -> HList xs -> r instance forall f z z' r x zx xs. ( zx ~ (z,x) , Apply f zx z' , HFoldl f z' xs r ) => HFoldl f z (x ': xs) r where hFoldl f z (x `HCons` xs) = hFoldl f (apply f (z,x) :: z') xs instance (z ~ z') => HFoldl f z '[] z' where hFoldl _ z _ = z -- | Like HFoldl but only use types, not values! -- -- It allows us to foldl over a list of types, without any associated hlist of -- values. class HFoldl' f (z :: *) xs (r :: *) where hFoldl' :: f -> z -> HList xs -> r instance forall f z z' r x zx xs. ( zx ~ (z,x) , Apply f zx z' , HFoldl' f z' xs r ) => HFoldl' f z (x ': xs) r where hFoldl' f z (_ `HCons` xs) = hFoldl' f (apply f (z,(undefined :: x)) :: z') xs instance (z ~ z') => HFoldl' f z '[] z' where hFoldl' _ z _ = z class HZipList x y l | x y -> l, l -> x y where hZipList :: HList x -> HList y -> HList l hUnzipList :: HList l -> (HList x, HList y) instance HZipList '[] '[] '[] where hZipList _ _ = HNil hUnzipList _ = (HNil, HNil) instance ((x,y)~z, HZipList xs ys zs) => HZipList (x ': xs) (y ': ys) (z ': zs) where hZipList (HCons x xs) (HCons y ys) = (x,y) `HCons` hZipList xs ys hUnzipList (HCons ~(x,y) zs) = let ~(xs,ys) = hUnzipList zs in (x `HCons` xs, y `HCons` ys) class HRevApp l1 l2 l3 | l1 l2 -> l3 where hRevApp :: HList l1 -> HList l2 -> HList l3 instance HRevApp '[] l2 l2 where hRevApp _ l = l instance HRevApp l (x ': l') z => HRevApp (x ': l) l' z where hRevApp (HCons x l) l' = hRevApp l (HCons x l') class HReverse xs sx | xs -> sx, sx -> xs where hReverse :: HList xs -> HList sx instance ( HRevApp xs '[] sx , HRevApp sx '[] xs ) => HReverse xs sx where hReverse l = hRevApp l HNil -------------------------------------- -- Tuple convertion -------------------------------------- -- * Conversion to and from tuples -- | Convert between hlists and tuples class HTuple' v t | v -> t, t -> v where -- | Convert an heterogeneous list into a tuple hToTuple' :: HList v -> t -- | Convert a tuple into an heterogeneous list hFromTuple' :: t -> HList v instance HTuple' '[] () where hToTuple' HNil = () hFromTuple' () = HNil instance HTuple' '[a] (Single a) where hToTuple' (a `HCons` HNil) = Single a hFromTuple' (Single a) = a `HCons` HNil instance HTuple' '[a,b] (a,b) where hToTuple' (a `HCons` b `HCons` HNil) = (a,b) hFromTuple' (a,b) = a `HCons` b `HCons` HNil instance HTuple' '[a,b,c] (a,b,c) where hToTuple' (a `HCons` b `HCons` c `HCons` HNil) = (a,b,c) hFromTuple' (a,b,c) = a `HCons` b `HCons` c `HCons` HNil instance HTuple' '[a,b,c,d] (a,b,c,d) where hToTuple' (a `HCons` b `HCons` c `HCons` d `HCons` HNil) = (a,b,c,d) hFromTuple' (a,b,c,d) = a `HCons` b `HCons` c `HCons` d `HCons` HNil instance HTuple' '[a,b,c,d,e] (a,b,c,d,e) where hToTuple' (a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` HNil) = (a,b,c,d,e) hFromTuple' (a,b,c,d,e) = a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` HNil instance HTuple' '[a,b,c,d,e,f] (a,b,c,d,e,f) where hToTuple' (a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` HNil) = (a,b,c,d,e,f) hFromTuple' (a,b,c,d,e,f) = a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` HNil instance HTuple' '[a,b,c,d,e,f,g] (a,b,c,d,e,f,g) where hToTuple' (a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` g `HCons` HNil) = (a,b,c,d,e,f,g) hFromTuple' (a,b,c,d,e,f,g) = a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` g `HCons` HNil instance HTuple' '[a,b,c,d,e,f,g,h] (a,b,c,d,e,f,g,h) where hToTuple' (a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` g `HCons` h `HCons` HNil) = (a,b,c,d,e,f,g,h) hFromTuple' (a,b,c,d,e,f,g,h) = a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` g `HCons` h `HCons` HNil instance HTuple' '[a,b,c,d,e,f,g,h,i] (a,b,c,d,e,f,g,h,i) where hToTuple' (a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` g `HCons` h `HCons` i `HCons` HNil) = (a,b,c,d,e,f,g,h,i) hFromTuple' (a,b,c,d,e,f,g,h,i) = a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` g `HCons` h `HCons` i `HCons` HNil instance HTuple' '[a,b,c,d,e,f,g,h,i,j] (a,b,c,d,e,f,g,h,i,j) where hToTuple' (a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` g `HCons` h `HCons` i `HCons` j `HCons` HNil) = (a,b,c,d,e,f,g,h,i,j) hFromTuple' (a,b,c,d,e,f,g,h,i,j) = a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` g `HCons` h `HCons` i `HCons` j `HCons` HNil