{-# LANGUAGE GADTs                 #-}
{-# LANGUAGE KindSignatures        #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies          #-}
{-# LANGUAGE TypeOperators         #-}
{-# LANGUAGE ScopedTypeVariables   #-}

module Base where

import Control.Applicative

-- * Structure types

infixr 5 :+:
infix  6 :>:
infixr 7 :*:

data I :: * -> (* -> *) -> (* -> *) -> * -> * where
  I :: Ix s xi => r xi -> I xi s r ix

unI :: I xi s r ix -> r xi
unI (I x) = x

data K a       (s :: * -> *) (r :: * -> *) ix = K {unK :: a}

data (f :+: g) (s :: * -> *) (r :: * -> *) ix = L (f s r ix) | R (g s r ix)
data (f :*: g) (s :: * -> *) (r :: * -> *) ix = f s r ix :*: g s r ix

data (:>:) :: ((* -> *) -> (* -> *) -> * -> *) -> * -> (* -> *) -> (* -> *) -> * -> * where
  Tag { unTag :: f s r ix } :: (f :>: ix) s r ix

-- ** Unlifted variants

newtype I0 a   = I0 { unI0 :: a }
newtype K0 a b = K0 { unK0 :: a }

instance Functor I0 where
  fmap f = I0 . f . unI0

instance Applicative I0 where
  pure              = I0
  (I0 f) <*> (I0 x) = I0 (f x)

-- * Indexed families

type family PF s :: (* -> *) -> (* -> *) -> * -> *
type Str s ix = (PF s) s I0 ix

class Ix s ix where
  from  :: ix -> Str s ix
  to    :: Str s ix -> ix
  index :: s ix

-- | Some functions need to have their types desugared in order to make programs
-- that use them typable.  Desugaring consists in transforming ``inline'' type
-- family applications into equality constraints. This is a strangeness in current
-- versions of GHC that hopefully will be fixed sometime in the future.

from'' :: forall s ix pfs . (Ix s ix, pfs ~ PF s) => ix -> pfs s I0 ix
from'' = from :: ix -> pfs s I0 ix

-- * Fixed point of indexed types

data HFix (h :: (* -> *) -> * -> *) ix = HIn { hout :: h (HFix h) ix }

