{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE PolyKinds #-}
module Haskus.Utils.Types.List
(
Snoc
, Concat
, Replicate
, Zip
, RemoveAt
, RemoveAt1
, RemoveAtN
, Remove
, Nub
, NubHead
, Head
, Last
, Tail
, Init
, Take
, Drop
, InsertAt
, ReplaceAt
, Replace
, ReplaceN
, ReplaceNS
, Subset
, SetEq
, CheckMember
, CheckMembers
, Union
, Complement
, Product
, Member
, Members
, CheckNub
, IndexOf
, IndexesOf
, MaybeIndexOf
, Index
, Elem
, MapElem
, Reverse
, Generate
, Map
, ListMax
, ListMin
, Length
, Indexes
, MapTest
)
where
import Haskus.Utils.Types.Bool
import Haskus.Utils.Types.Error
import Haskus.Utils.Types.Nat
import Haskus.Utils.Types.Constraint
type family Map (f :: a -> k) (xs :: [a]) :: [k] where
Map f '[] = '[]
Map f (x ': xs) = f x ': Map f xs
type family ListMax (xs :: [Nat]) where
ListMax (x ': xs) = Max' x xs
type family Max' (x :: Nat) (xs :: [Nat]) where
Max' x '[] = x
Max' x (a ': xs) = Max' (If (x <=? a) a x) xs
type family ListMin (xs :: [Nat]) where
ListMin (x ': xs) = Min' x xs
type family Min' (x :: Nat) (xs :: [Nat]) where
Min' x '[] = x
Min' x (a ': xs) = Min' (If (x <=? a) x a) xs
type family Tail (xs :: [k]) :: [k] where
Tail (x ': xs) = xs
type family Drop (n :: Nat) (xs :: [k]) :: [k] where
Drop 0 xs = xs
Drop n (x ': xs) = Drop (n-1) xs
type family Take (n :: Nat) (xs :: [k]) :: [k] where
Take 0 xs = '[]
Take n (x ': xs) = x ': (Take (n-1) xs)
type family Init (xs :: [k]) :: [k] where
Init '[x] = '[]
Init (x ': xs) = x ': (Init xs)
type family Snoc (xs :: [k]) (x :: k) :: [k] where
Snoc '[] x = '[x]
Snoc (y ': ys) x = y ': (Snoc ys x)
type family Head (xs :: [k]) :: k where
Head (x ': xs) = x
type family Last (xs :: [k]) :: k where
Last '[x] = x
Last (x ': xs) = Last xs
type family Concat (xs :: [k]) (ys :: [k]) :: [k] where
Concat '[] '[] = '[]
Concat '[] ys = ys
Concat (x ': xs) ys = x ': Concat xs ys
type family Length (xs :: [k]) :: Nat where
Length xs = Length' 0 xs
type family Length' n (xs :: [k]) :: Nat where
Length' n '[] = n
Length' n (x ': xs) = Length' (n+1) xs
type family Replicate (n :: Nat) (s :: k) :: [k] where
Replicate n s = Replicate' s n '[]
type family Replicate' (x :: k) (n :: Nat) (xs :: [k]) :: [k] where
Replicate' x 0 xs = xs
Replicate' x n xs = Replicate' x (n-1) (x ': xs)
type family InsertAt (n :: Nat) (l :: [k]) (l2 :: [k]) :: [k] where
InsertAt 0 xs ys = Concat ys xs
InsertAt n (x ': xs) ys = x ': InsertAt (n-1) xs ys
type family ReplaceAt (n :: Nat) (l :: [k]) (l2 :: [k]) :: [k] where
ReplaceAt 0 (x ': xs) ys = Concat ys xs
ReplaceAt n (x ': xs) ys = x ': ReplaceAt (n-1) xs ys
type family Replace (t1 :: k) (t2 :: k) (l :: [k]) :: [k] where
Replace t1 t2 '[] = '[]
Replace t1 t2 (t1 ': xs) = t2 ': (Replace t1 t2 xs)
Replace t1 t2 (x ': xs) = x ': (Replace t1 t2 xs)
type family ReplaceN (n :: Nat) (t :: k) (l :: [k]) :: [k] where
ReplaceN 0 t (x ': xs) = (t ': xs)
ReplaceN n t (x ': xs) = x ': ReplaceN (n-1) t xs
type family ReplaceNS (ns :: [Nat]) (t :: k) (l :: [k]) :: [k] where
ReplaceNS '[] t l = l
ReplaceNS (i ': is) t l = ReplaceNS is t (ReplaceN i t l)
type family Reverse (l :: [k]) :: [k] where
Reverse l = Reverse' l '[]
type family Reverse' (l :: [k]) (l2 :: [k]) :: [k] where
Reverse' '[] l = l
Reverse' (x ': xs) l = Reverse' xs (x ': l)
type family RemoveAt (n :: Nat) (l :: [k]) :: [k] where
RemoveAt 0 (x ': xs) = xs
RemoveAt n (x ': xs) = x ': RemoveAt (n-1) xs
type family RemoveAt1 (n :: Nat) (l :: [k]) :: [k] where
RemoveAt1 0 xs = xs
RemoveAt1 1 (x ': xs) = xs
RemoveAt1 n (x ': xs) = x ': RemoveAt1 (n-1) xs
type family RemoveAtN (ns :: [Nat]) (l :: [k]) :: [k] where
RemoveAtN '[] xs = xs
RemoveAtN (i ': is) xs = RemoveAtN is (RemoveAt i xs)
type family Generate (n :: Nat) (m :: Nat) :: [Nat] where
Generate n n = '[]
Generate n m = n ': Generate (n+1) m
type family CheckMember (a :: k) (l :: [k]) :: Constraint where
CheckMember a l = CheckMember' (MaybeIndexOf a l) a l
type family CheckMember' (i :: Nat) (a :: k) (l :: [k]) :: Constraint where
CheckMember' 0 a l = TypeError ( 'Text "`"
':<>: 'ShowType a
':<>: 'Text "'"
':<>: 'Text " is not a member of "
':<>: 'ShowType l)
CheckMember' _ _ _ = ()
type family CheckMembers (l1 :: [k]) (l2 :: [k]) :: Constraint where
CheckMembers '[] l1 = ()
CheckMembers (x ': xs) l2 = CheckMembers' (MaybeIndexOf x l2) x xs (x ': xs) l2
type family CheckMembers' (i :: Nat) (x :: k) (xs :: [k]) (l1 :: [k]) (l2 :: [k]) :: Constraint where
CheckMembers' 0 x _ l1 l2 = TypeError ( 'ShowType l1
':$$: 'Text "is not a subset of"
':$$: 'ShowType l2
':$$: 'ShowType x
':<>: 'Text " is missing from the latter.")
CheckMembers' _ _ '[] _ _ = ()
CheckMembers' _ _ (x ': xs) l1 l2 = CheckMembers' (MaybeIndexOf x l2) x xs l1 l2
type family Indexes (l :: [k]) :: [Nat] where
Indexes xs = IndexesFrom 0 xs
type family IndexesFrom (n :: Nat) (xs :: [k]) :: [Nat] where
IndexesFrom n '[] = '[]
IndexesFrom n (x ': xs) = n ': IndexesFrom (n+1) xs
type family MapTest (a :: k) (l :: [k]) :: [Nat] where
MapTest a '[] = '[]
MapTest a (a ': xs) = 1 ': MapTest a xs
MapTest a (x ': xs) = 0 ': MapTest a xs
type family Zip (l :: [*]) (l2 :: [*]) where
Zip '[] xs = '[]
Zip xs '[] = '[]
Zip (x ': xs) (y ': ys) = (x,y) ': Zip xs ys
type family Remove (a :: k) (l :: [k]) :: [k] where
Remove a '[] = '[]
Remove a (a ': as) = Remove a as
Remove a (b ': as) = b ': Remove a as
type family Nub (l :: [k]) :: [k] where
Nub xs = Reverse (Nub' xs '[])
type family Nub' (as :: [k]) (xs :: [k]) :: [k] where
Nub' '[] xs = xs
Nub' (x ': as) xs = Nub' (Remove x as) (x ': xs)
type family NubHead (l :: [k]) :: [k] where
NubHead '[] = '[]
NubHead (x ': xs) = x ': Remove x xs
type IndexOf (x :: k) (xs :: [k]) = IndexOf' (MaybeIndexOf x xs) x xs
type family IndexOf' (i :: Nat) (a :: k) (l :: [k]) :: Nat where
IndexOf' 0 x l = TypeError ( 'ShowType x
':<>: 'Text " not found in list:"
':$$: 'Text " "
':<>: 'ShowType l )
IndexOf' i _ _ = i - 1
type family IndexesOf (a :: k) (l :: [k]) :: [Nat] where
IndexesOf x xs = IndexesOf' 0 x xs
type family IndexesOf' n (a :: k) (l :: [k]) :: [Nat] where
IndexesOf' n x '[] = '[]
IndexesOf' n x (x ': xs) = n ': IndexesOf' (n+1) x xs
IndexesOf' n x (y ': xs) = IndexesOf' (n+1) x xs
type family MaybeIndexOf (a :: k) (l :: [k]) where
MaybeIndexOf x xs = MaybeIndexOf' 0 x xs
type family MaybeIndexOf' (n :: Nat) (a :: k) (l :: [k]) where
MaybeIndexOf' n x '[] = 0
MaybeIndexOf' n x (x ': xs) = n + 1
MaybeIndexOf' n x (y ': xs) = MaybeIndexOf' (n+1) x xs
type Index (n :: Nat) (l :: [k]) = Index' n l l
type family Index' (n :: Nat) (l :: [k]) (l2 :: [k]) :: k where
Index' 0 (x ': _ ) _ = x
Index' n (_ ': xs) l2 = Index' (n-1) xs l2
Index' n '[] l2 = TypeError ( 'Text "Index "
':<>: 'ShowType n
':<>: 'Text " out of bounds for list:"
':$$: 'Text " "
':<>: 'ShowType l2 )
type family Elem (t :: b) (f :: b) (x :: k) (xs :: [k]) :: b where
Elem t f x '[] = f
Elem t f x (x ': xs) = t
Elem t f x (y ': xs) = Elem t f x xs
type family MapElem (t :: b) (f :: b) (xs :: [a]) (ys :: [a]) :: [b] where
MapElem t f '[] ys = '[]
MapElem t f (x ': xs) ys = Elem t f x ys ': MapElem t f xs ys
type family Subset (t :: b) (f :: b) (xs :: [a]) (ys :: [a]) :: b where
Subset t f '[] '[] = t
Subset t f xs ys = AndMany t f (MapElem t f xs ys)
type family SetEq (t :: b) (f :: b) (xs :: [a]) (ys :: [a]) :: b where
SetEq t f xs ys = And t f (Subset t f xs ys)
(Subset t f ys xs)
type family Union (xs :: [k]) (ys :: [k]) :: [k] where
Union xs ys = Nub (Concat xs ys)
type family Complement (xs :: [k]) (ys :: [k]) :: [k] where
Complement xs '[] = xs
Complement xs (y:ys) = Complement (Remove y xs) ys
type family Product (xs :: [*]) (ys :: [*]) :: [*] where
Product '[] ys = '[]
Product xy '[] = '[]
Product (x:xs) ys = Concat (Product' x ys) (Product xs ys)
type family Product' (x :: *) (ys :: [*]) :: [*] where
Product' x '[] = '[]
Product' x (y ': ys) = (x,y) ': Product' x ys
type family Member x xs :: Constraint where
Member x xs = MemberAtIndex (IndexOf x xs) x xs
type MemberAtIndex i x xs =
( x ~ Index i xs
, KnownNat i
)
type family Members xs ys :: Constraint where
Members '[] ys = ()
Members (x ': xs) ys = (Member x ys, Members xs ys)
type CheckNub (l :: [k]) =
( CheckNubEx l (Nub l) ~ 'True
)
type family CheckNubEx (l1 :: [k]) (l2 :: [k]) where
CheckNubEx l l = 'True
CheckNubEx l1 l2 = TypeError
( 'Text "Type-list contains unallowed redundant types."
':$$: 'Text "Got: " ':<>: 'ShowType l1
':$$: 'Text "Expected: " ':<>: 'ShowType l2
)