{-# LANGUAGE GADTs, ExistentialQuantification, EmptyDataDecls #-}

--- Slightly more complicated GADT example
--- Natural numbers and Length-indexed lists

module NList where
-- safe to export everything

-- natural numbers 
data Z 
data S x 

data List n b where 
  Nil  :: List Z a 
  Cons :: a -> List n a -> List (S n) a

instance Show b => Show (List n b) where
    show Nil = "nil"
    show (Cons x xs) = "(cons " ++ show x ++ " " ++ show xs ++ ")"

-- No definitions of nil/cons

sHead :: List (S n) b -> b
sHead (Cons x xs) = x

sTail :: List (S n) b -> List n b
sTail (Cons x xs) = xs

-- Bounded natural numbers. I.e. a number m that 
--    is less than some other number n
data LT n where
    Z :: LT (S n)
    S :: LT n -> LT (S n)

coerce :: LT n -> LT (S n)
coerce Z = Z
coerce (S n) = S (coerce n)

{-
check  :: Singlton n -> LT (S n) -> Maybe ( LT n )
check Z     = Nothing
check (S Z) = Just (S Z)
-- n1 :: LT n
check (S n1@(S _)) = do m <- check n1
                        return (S m)
-}



toInt :: LT n -> Int
toInt Z = 0
toInt (S n) = 1 + toInt n

instance Show (LT n) where
  show n = show (toInt n)

-- only lookup at a position less than the length of the list

cLookup :: LT n -> List m a -> Maybe a
cLookup Z (Cons x xs) = Just x
cLookup (S n) (Cons x xs) = cLookup n xs
cLookup _ Nil = Nothing

cLookup' :: LT n -> List m a -> Maybe (LT m)
cLookup' Z (Cons x xs)     = Just Z
cLookup' (S n) (Cons x xs) = do n' <- (cLookup' n xs)
                                return (S n')
cLookup' _ Nil = Nothing

x :: List (S (S (S (S Z)))) Int
x = (Cons 1 (Cons 2 Nil)) 

y :: LT (S (S (S Z)))
y = (S (S Z))

sLookup :: LT n -> List n a -> a
sLookup Z     (Cons x xs) = x
sLookup (S n) (Cons x xs) = sLookup n xs








