{-# language DataKinds #-}
{-# language TypeOperators #-}
{-# language GADTs #-}
{-# language TypeFamilies #-}
{-# language KindSignatures #-}
{-# language TypeInType #-}
{-# language PatternSynonyms #-}
{-# language UndecidableInstances #-}
{-# language FlexibleContexts #-}
{-# language FlexibleInstances #-}
{-# language ScopedTypeVariables #-}
{-# language MultiParamTypeClasses #-}
{-# language FunctionalDependencies #-}
{-# language ConstraintKinds #-}
module Data.PolyKinded (
LoT(..), (:@@:), LoT1, LoT2
, HeadLoT, TailLoT, SpineLoT
, SLoT(..), SForLoT(..), Proxy(..)
, SplitF, Nat(..), TyEnv(..), SplitN
) where
import Data.Proxy
infixr 5 :&&:
data LoT k where
LoT0 :: LoT (*)
(:&&:) :: k -> LoT ks -> LoT (k -> ks)
type LoT1 a = a ':&&: 'LoT0
type LoT2 a b = a ':&&: b ':&&: LoT0
type family (f :: k) :@@: (tys :: LoT k) :: * where
f :@@: _ = f
f :@@: as = f (HeadLoT as) :@@: (TailLoT as)
type family HeadLoT (tys :: LoT (k -> k')) :: k where
HeadLoT (a :&&: _) = a
type family TailLoT (tys :: LoT (k -> k')) :: LoT k' where
TailLoT (_ :&&: as) = as
type family SpineLoT (ts :: LoT k) :: LoT k where
SpineLoT (ts :: LoT (k -> k')) = HeadLoT ts :&&: SpineLoT (TailLoT ts)
SpineLoT (ts :: LoT (*)) = LoT0
data SLoT (l :: LoT k) where
SLoT0 :: SLoT LoT0
SLoTA :: Proxy t -> SLoT ts -> SLoT (t :&&: ts)
class SForLoT (l :: LoT k) where
slot :: SLoT l
instance (l ~ LoT0) => SForLoT (l :: LoT (*)) where
slot = SLoT0
instance (l ~ (t :&&: ts), SForLoT ts) => SForLoT (l :: LoT (k -> k')) where
slot = SLoTA Proxy slot
type SplitF (t :: d) (f :: k) = SplitF' t f 'LoT0
type family SplitF' (t :: d) (f :: k) (p :: LoT l) :: LoT k where
SplitF' f f acc = acc
SplitF' (t a) f acc = SplitF' t f (a ':&&: acc)
data Nat = Z | S Nat
data TyEnv where
TyEnv :: forall k. k -> LoT k -> TyEnv
type family SplitN (n :: Nat) t :: TyEnv where
SplitN n t = SplitN' n t 'LoT0
type family SplitN' (n :: Nat) (t :: d) (p :: LoT d) :: TyEnv where
SplitN' 'Z t acc = 'TyEnv t acc
SplitN' ('S n) (t (a :: l)) acc = SplitN' n t (a ':&&: acc)