clr-typed-0.2.0: src/Clr/ListTuple.hs
{-# LANGUAGE TypeInType, PolyKinds, TypeFamilies, MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances, FlexibleContexts, UndecidableInstances #-}
{-# LANGUAGE AllowAmbiguousTypes, FunctionalDependencies, TypeOperators #-}
module Clr.ListTuple where
import Data.Kind
import Data.Type.Bool
import Data.Type.Equality
import GHC.TypeLits
--
-- List to tuple conversion
--
type family ListToTuple (t :: [Type]) :: Type where
ListToTuple '[] = ()
ListToTuple (a ': '[]) = (a)
ListToTuple (a ': b ': '[]) = (a,b)
ListToTuple (a ': b ': c ': '[]) = (a,b,c)
ListToTuple (a ': b ': c ': d ': '[]) = (a,b,c,d)
ListToTuple (a ': b ': c ': d ': e ': '[]) = (a,b,c,d,e)
ListToTuple (a ': b ': c ': d ': e ': f ': '[]) = (a,b,c,d,e,f)
ListToTuple (a ': b ': c ': d ': e ': f ': g ': '[]) = (a,b,c,d,e,f,g)
ListToTuple (a ': b ': c ': d ': e ': f ': g ': h ': '[]) = (a,b,c,d,e,f,g,h)
ListToTuple (a ': b ': c ': d ': e ': f ': g ': h ': i ': '[]) = (a,b,c,d,e,f,g,h,i)
ListToTuple (a ': b ': c ': d ': e ': f ': g ': h ': i ': j ': '[]) = (a,b,c,d,e,f,g,h,i,j)
ListToTuple (a ': b ': c ': d ': e ': f ': g ': h ': i ': j ': k ': '[]) = (a,b,c,d,e,f,g,h,i,j,k)
--
-- Tuple to list conversion
--
type family TupleToList (t::Type) :: [Type] where
TupleToList () = '[]
TupleToList (a,b) = '[a, b]
TupleToList (a,b,c) = '[a, b, c]
TupleToList (a,b,c,d) = '[a, b, c, d]
TupleToList (a,b,c,d,e) = '[a, b, c, d, e]
TupleToList (a,b,c,d,e,f) = '[a, b, c, d, e, f]
TupleToList (a,b,c,d,e,f,g) = '[a, b, c, d, e, f, g]
TupleToList (a,b,c,d,e,f,g,h) = '[a, b, c, d, e, f, g, h]
TupleToList (a,b,c,d,e,f,g,h,i) = '[a, b, c, d, e, f, g, h, i]
TupleToList (a,b,c,d,e,f,g,h,i,j) = '[a, b, c, d, e, f, g, h, i, j]
TupleToList (a,b,c,d,e,f,g,h,i,j,k) = '[a, b, c, d, e, f, g, h, i, j, k]
TupleToList (a) = '[a] -- NB: "(a)" denotes anything that didn't match above, this could be either a non-tuple or a tuple bigger than what above could match on
--
-- Size of a tuple
--
type family TupleSize (x::tupleKind) :: Nat where
TupleSize a = ListSize (TupleToList a) -- NB: the size of '()' is considered 0, and anything non tuple or bigger than what 'TupleToList' matches on is 1.
--
-- ArgCount is like TupleSize, except evaluates to 1 for '()', which only makes sens given how it is currently used
--
type family ArgCount (x::tupleKind) :: Nat where
ArgCount () = 1
ArgCount a = TupleSize a
--
-- Size of a list
--
type family ListSize (x::k) :: Nat where
ListSize '[] = 0
ListSize (x ': xs) = 1 + (ListSize xs)
--
-- a `Elem` xs is true if a is contained within xs
--
type family Elem (a :: k) (xs::[k]) :: Bool where
Elem a '[] = 'False
Elem a (x ': xs) = a == x || (Elem a xs)
--
-- Concatenate a type level list of lists
--
type family Concat (a::[[t]]) :: [t] where
Concat '[] = '[]
Concat (x ': xs) = x `Append` (Concat xs)
--
-- Append 2 type level lists
--
type family Append (a::[t]) (b::[t]) :: [t] where
Append '[] ys = ys
Append (x ': xs) ys = x ': (xs `Append` ys)
--
-- Drops each Nothing from a list and does a fromJust on the others
--
type family CatMaybes (l :: [Maybe k]) :: [k] where
CatMaybes '[] = '[]
CatMaybes ('Just x ': xs) = x ': CatMaybes xs
CatMaybes ('Nothing ': xs) = CatMaybes xs
--
-- PrependIf b x xs evaluates to xs when b is false and x : xs when b is true
--
type family PrependIf (b :: Bool) (x :: k) (xs :: [k]) :: [k] where
PrependIf 'True x xs = x ': xs
PrependIf 'False x xs = xs
type family Index (x::[t]) (n::Nat) :: t where
Index (x ': xs) 0 = x
Index (x ': xs) n = Index xs (n-1)
Index xs n = TypeError (Text "Out of bounds")